home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 September / Chip_2002-09_cd1.bin / sharewar / slunec / app / httrack.exe / {app} / src / htslib.c < prev    next >
C/C++ Source or Header  |  2002-07-17  |  108KB  |  4,030 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: Subroutines                                            */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. // Fichier librairie .c
  38.  
  39. #include "htslib.h"
  40. #include "htsbauth.h"
  41.  
  42. /* specific definitions */
  43. #include "htsbase.h"
  44. #include "htsnet.h"
  45. #include "htsbauth.h"
  46. #include "htsthread.h"
  47. #include "htsnostatic.h"
  48. #include "htswrap.h"
  49. #include <stdio.h>
  50. #if HTS_WIN
  51. #include <direct.h>
  52. #else
  53. #include <unistd.h>
  54. #endif
  55. #include <stdlib.h>
  56. #include <string.h>
  57. #include <time.h>
  58. #include <sys/timeb.h>
  59. #include <fcntl.h>
  60. // pour utimbuf
  61. #if HTS_WIN
  62. #include <sys/utime.h>
  63. #else
  64. #if HTS_PLATFORM!=3
  65. #include <utime.h>
  66. #else
  67. #include <utime.h>
  68. #endif
  69. #endif
  70. /* END specific definitions */
  71.  
  72.  
  73.  
  74. // DΘbuggage de contr⌠le
  75. #if HTS_DEBUG_CLOSESOCK
  76. #define _HTS_WIDE 1
  77. #endif
  78. #if HTS_WIDE_DEBUG
  79. #define _HTS_WIDE 1
  80. #endif
  81. #if _HTS_WIDE
  82. FILE* DEBUG_fp=NULL;
  83. #define DEBUG_W(A)  { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,":>"A); fflush(DEBUG_fp); }
  84. #define DEBUG_W2(A) { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,A); fflush(DEBUG_fp); }
  85. #endif
  86.  
  87. /* variables globales */
  88. int _DEBUG_HEAD;
  89. FILE* ioinfo;
  90.  
  91. #if HTS_USEOPENSSL
  92.  SSL_CTX *openssl_ctx = NULL;
  93. #endif
  94.  
  95. /* dΘtection complΘmentaire */
  96. const char hts_detect[][32] = {
  97.   "archive",
  98.   "background",
  99.   "data",         // OBJECT
  100.   "dynsrc",
  101.   "lowsrc",
  102.   "profile",      // element META
  103.   "src",
  104.   "swurl",
  105.   "url",
  106.   "usemap",
  107.   "longdesc",     // accessibility
  108.   "xlink:href",   // xml/svg tag
  109.   ""
  110. };
  111.  
  112. /* dΘtecter dΘbut */
  113. const char hts_detectbeg[][32] = {
  114.   "hotspot",      /* hotspot1=..,hotspot2=.. */
  115.   ""
  116. };
  117.  
  118. /* ne pas dΘtcter de liens dedans */
  119. const char hts_nodetect[][32] = {
  120.   "accept-charset",
  121.   "accesskey",
  122.   "action",
  123.   "align",
  124.   "alt",
  125.   "axes",
  126.   "axis",
  127.   "char",
  128.   "charset",
  129.   "cite",
  130.   "class",
  131.   "classid",
  132.   "code",
  133.   "color",
  134.   "datetime",
  135.   "dir",
  136.   "enctype",
  137.   "face",
  138.   "height",
  139.   "id",
  140.   "lang",
  141.   "language",
  142.   "media",
  143.   "method",
  144.   "name",
  145.   "prompt",
  146.   "scheme",
  147.   "size",
  148.   "style",
  149.   "target",
  150.   "title",
  151.   "type",
  152.   "valign",
  153.   "version",
  154.   "width",
  155.   ""
  156. };
  157.  
  158.  
  159. /* dΘtection de mini-code javascript */
  160. /* ALSO USED: detection based on the name: onXXX="<tag>" where XXX starts with upper case letter */
  161. const char hts_detect_js[][32] = {
  162.   "onAbort",
  163.   "onBlur",
  164.   "onChange",
  165.   "onClick",
  166.   "onDblClick",
  167.   "onDragDrop",
  168.   "onError",
  169.   "onFocus",
  170.   "onKeyDown",
  171.   "onKeyPress",
  172.   "onKeyUp",
  173.   "onLoad",
  174.   "onMouseDown",
  175.   "onMouseMove",
  176.   "onMouseOut",
  177.   "onMouseOver",
  178.   "onMouseUp",
  179.   "onMove",
  180.   "onReset",
  181.   "onResize",
  182.   "onSelect",
  183.   "onSubmit",
  184.   "onUnload",
  185.   ""
  186. };
  187.  
  188. /* dΘtection "...URL=<url>" */
  189. const char hts_detectURL[][32] = {
  190.   "content",
  191.   ""
  192. };
  193.  
  194. /* tags o∙ l'URL doit Ωtre rΘΘcrite mais non capturΘe */
  195. const char hts_detectandleave[][32] = {
  196.   "action",
  197.   ""
  198. };
  199.  
  200. /* ne pas renommer les types renvoyΘs (couvent types inconnus) */
  201. const char hts_mime_keep[][32] = {
  202.   "application/octet-stream",
  203.   "text/plain",
  204.   ""
  205. };
  206.  
  207. /* pas de type mime connu, mais extension connue */
  208. const char hts_ext_dynamic[][32] = {
  209.   "php3",
  210.   "php",
  211.   "php4",
  212.   "php2",
  213.   "cgi",
  214.   "asp",
  215.   "jsp",
  216.   "pl",
  217.   /*"exe",*/
  218.   "cfm",
  219.   ""
  220. };
  221.  
  222. /* types MIME */
  223. const char hts_mime[][2][32] = {
  224.   {"application/acad","dwg"},
  225.   {"application/arj","arj"},
  226.   {"application/clariscad","ccad"},
  227.   {"application/drafting","drw"},
  228.   {"application/dxf","dxf"},
  229.   {"application/excel","xl"},
  230.   {"application/i-deas","unv"},
  231.   {"application/iges","isg"},
  232.   {"application/iges","iges"},
  233.   {"application/mac-binhex40","hqx"},
  234.   {"application/mac-compactpro","cpt"},
  235.   {"application/msword","doc"},
  236.   {"application/msword","w6w"},
  237.   {"application/msword","word"},
  238.   {"application/mswrite","wri"},
  239.   /*{"application/octet-stream","dms"},*/
  240.   /*{"application/octet-stream","lzh"},*/
  241.   /*{"application/octet-stream","lha"},*/
  242.   /*{"application/octet-stream","bin"},*/
  243.   {"application/oda","oda"},
  244.   {"application/pdf","pdf"},
  245.   {"application/postscript","ps"},
  246.   {"application/postscript","ai"},
  247.   {"application/postscript","eps"},
  248.   {"application/powerpoint","ppt"},
  249.   {"application/pro_eng","prt"},
  250.   {"application/pro_eng","part"},
  251.   {"application/rtf","rtf"},
  252.   {"application/set","set"},
  253.   {"application/sla","stl"},
  254.   {"application/smil","smi"},
  255.   {"application/smil","smil"},
  256.   {"application/smil","sml"},
  257.   {"application/solids","sol"},
  258.   {"application/STEP","stp"},
  259.   {"application/STEP","step"},
  260.   {"application/vda","vda"},
  261.   {"application/x-authorware-map","aam"},     
  262.   {"application/x-authorware-seg","aas"},
  263.   {"application/x-authorware-bin","aab"},
  264.   {"application/x-cocoa","cco"},
  265.   {"application/x-csh","csh"},
  266.   {"application/x-director","dir"},
  267.   {"application/x-director","dcr"},
  268.   {"application/x-director","dxr"},
  269.   {"application/x-mif","mif"},
  270.   {"application/x-dvi","dvi"},
  271.   {"application/x-gzip","gz"},
  272.   {"application/x-gzip","gzip"},
  273.   {"application/x-hdf","hdf"},
  274.   {"application/x-javascript","js"},
  275.   {"application/x-koan","skp"},
  276.   {"application/x-koan","skd"},
  277.   {"application/x-koan","skt"},
  278.   {"application/x-koan","skm"},
  279.   {"application/x-latex","latex"},
  280.   {"application/x-netcdf","nc"},
  281.   {"application/x-netcdf","cdf"},
  282.   /* {"application/x-sh","sh"}, */
  283.   /* {"application/x-csh","csh"}, */
  284.   /* {"application/x-ksh","ksh"}, */
  285.   {"application/x-shar","shar"},
  286.   {"application/x-stuffit","sit"},
  287.   {"application/x-tcl","tcl"},
  288.   {"application/x-tex","tex"},
  289.   {"application/x-texinfo","texinfo"},
  290.   {"application/x-texinfo","texi"},
  291.   {"application/x-troff","t"},
  292.   {"application/x-troff","tr"},
  293.   {"application/x-troff","roff"},
  294.   {"application/x-troff-man","man"},
  295.   {"application/x-troff-me","ms"},
  296.   {"application/x-wais-source","src"},
  297.   {"application/zip","zip"},
  298.   {"application/x-zip-compressed","zip"},
  299.   {"application/x-bcpio","bcpio"},
  300.   {"application/x-cdlink","vcd"},
  301.   {"application/x-cpio","cpio"},
  302.   {"application/x-gtar","tgz"},
  303.   {"application/x-gtar","gtar"},
  304.   {"application/x-shar","shar"},
  305.   {"application/x-shockwave-flash","swf"},
  306.   {"application/x-sv4cpio","sv4cpio"},
  307.   {"application/x-sv4crc","sv4crc"},
  308.   {"application/x-tar","tar"},
  309.   {"application/x-ustar","ustar"},
  310.   {"application/x-winhelp","hlp"},
  311.   {"audio/midi","mid"},
  312.   {"audio/midi","midi"},
  313.   {"audio/midi","kar"},
  314.   {"audio/mpeg","mp3"},
  315.   {"audio/mpeg","mpga"},
  316.   {"audio/mpeg","mp2"},
  317.   {"audio/basic","au"},
  318.   {"audio/basic","snd"},
  319.   {"audio/x-aiff","aif"},
  320.   {"audio/x-aiff","aiff"},
  321.   {"audio/x-aiff","aifc"},
  322.   {"audio/x-pn-realaudio","rm"},
  323.   {"audio/x-pn-realaudio","ram"},
  324.   {"audio/x-pn-realaudio","ra"},
  325.   {"audio/x-pn-realaudio-plugin","rpm"},
  326.   {"audio/x-wav","wav"},
  327.   {"chemical/x-pdb","pdb"},
  328.   {"chemical/x-pdb","xyz"},
  329.   {"drawing/x-dwf","dwf"},
  330.   {"image/gif","gif"},
  331.   {"image/ief","ief"},
  332.   {"image/jpeg","jpg"},
  333.   {"image/jpeg","jpe"},
  334.   {"image/jpeg","jpeg"},
  335.   {"image/pict","pict"},
  336.   {"image/png","png"},
  337.   {"image/tiff","tiff"},
  338.   {"image/tiff","tif"},
  339.   {"image/svg+xml","svg"},
  340.   {"image/x-cmu-raster","ras"},
  341.   {"image/x-freehand","fh4"},
  342.   {"image/x-freehand","fh7"},
  343.   {"image/x-freehand","fh5"},  
  344.   {"image/x-freehand","fhc"},
  345.   {"image/x-freehand","fh"},   
  346.   {"image/x-portable-anymap","pnm"},
  347.   {"image/x-portable-bitmap","pgm"},
  348.   {"image/x-portable-pixmap","ppm"},
  349.   {"image/x-rgb","rgb"},
  350.   {"image/x-xbitmap","xbm"},
  351.   {"image/x-xpixmap","xpm"},
  352.   {"image/x-xwindowdump","xwd"},
  353.   {"model/mesh","msh"},  
  354.   {"model/mesh","mesh"},  
  355.   {"model/mesh","silo"},  
  356.   {"multipart/x-zip","zip"},
  357.   {"multipart/x-gzip","gzip"},
  358.   {"text/css","css"},
  359.   {"text/html","html"},
  360.   {"text/html","htm"},
  361.   {"text/plain","txt"},
  362.   {"text/plain","g"},
  363.   {"text/plain","h"},
  364.   {"text/plain","c"},
  365.   {"text/plain","cc"},
  366.   {"text/plain","hh"},
  367.   {"text/plain","m"},
  368.   {"text/plain","f90"},
  369.   {"text/richtext","rtx"},
  370.   {"text/tab-separated-values","tsv"},
  371.   {"text/x-setext","etx"},
  372.   {"text/x-sgml","sgml"},
  373.   {"text/x-sgml","sgm"},
  374.   {"text/xml","xml"},  
  375.   {"text/xml","dtd"},  
  376.   {"video/mpeg","mpeg"},
  377.   {"video/mpeg","mpg"},
  378.   {"video/mpeg","mpe"},
  379.   {"video/quicktime","qt"},
  380.   {"video/quicktime","mov"},
  381.   {"video/x-msvideo","avi"},
  382.   {"video/x-sgi-movie","movie"},
  383.   {"x-conference/x-cooltalk","ice"},
  384.   /*{"application/x-httpd-cgi","cgi"},*/
  385.   {"x-world/x-vrml","wrl"},
  386.   
  387.   {"*","class"},
  388.   
  389.   {"",""}};
  390.  
  391.  
  392. // Reserved (RFC2396)
  393. #define CHAR_RESERVED(c)  ( strchr(";/?:@&=+$,",(unsigned char)(c)) != 0 )
  394. // Delimiters (RFC2396)
  395. #define CHAR_DELIM(c)     ( strchr("<>#%\"",(unsigned char)(c)) != 0 )
  396. // Unwise (RFC2396)
  397. #define CHAR_UNWISE(c)    ( strchr("{}|\\^[]`",(unsigned char)(c)) != 0 )
  398. // Special (escape chars) (RFC2396 + >127 )
  399. #define CHAR_LOW(c)       ( ((unsigned char)(c) <= 31) )
  400. #define CHAR_HIG(c)       ( ((unsigned char)(c) >= 127) )
  401. #define CHAR_SPECIAL(c)   ( CHAR_LOW(c) || CHAR_HIG(c) )
  402. // We try to avoid them and encode them instead
  403. #define CHAR_XXAVOID(c)   ( strchr(" *'\"!",(unsigned char)(c)) != 0 )
  404.  
  405.  
  406. // conversion Θventuelle / vers antislash
  407. #if HTS_WIN
  408. char* antislash(char* s) {
  409.   char* buff;
  410.   char* a;
  411.   NOSTATIC_RESERVE(buff, char, HTS_URLMAXSIZE*2);
  412.  
  413.   strcpy(buff,s);
  414.   while(a=strchr(buff,'/')) *a='\\';
  415.   return buff;
  416. }
  417. #endif
  418.  
  419.  
  420.  
  421. // RΘcupΘration d'un fichier http sur le net.
  422. // Renvoie une adresse sur le bloc de mΘmoire, ou bien
  423. // NULL si un retour.msgeur (buffer retour.msg) est survenue. 
  424. //
  425. // Une adresse de structure htsmsg peut Ωtre transmise pour
  426. // suivre l'Θvolution du chargement si le process a ΘtΘ lancΘ 
  427. // en background
  428.  
  429. htsblk httpget(char* url) {
  430.   char adr[HTS_URLMAXSIZE*2];   // adresse
  431.   char fil[HTS_URLMAXSIZE*2];   // chemin
  432.   
  433.   // sΘparer URL en adresse+chemin
  434.   if (ident_url_absolute(url,adr,fil)==-1) {
  435.     htsblk retour;
  436.     memset(&retour, 0, sizeof(htsblk));    // effacer
  437.     // retour prΘdΘfini: erreur
  438.     retour.adr=NULL;
  439.     retour.size=0;
  440.     retour.msg[0]='\0';
  441.     retour.statuscode=-1;    
  442.     strcpy(retour.msg,"Error invalid URL");
  443.     return retour;
  444.   }
  445.   
  446.   return xhttpget(adr,fil);
  447. }
  448.  
  449. // ouvre une liaison http, envoie une requΦte GET et rΘceptionne le header
  450. // retour: socket
  451. int http_fopen(char* adr,char* fil,htsblk* retour) {
  452.   //                / GET, traiter en-tΩte
  453.   return http_xfopen(0,1,1,NULL,adr,fil,retour);
  454. }
  455.  
  456. // ouverture d'une liaison http, envoi d'une requΦte
  457. // mode: 0 GET  1 HEAD  [2 POST]
  458. // treat: traiter header?
  459. // waitconnect: attendre le connect()
  460. // note: dans retour, on met les params du proxy
  461. int http_xfopen(int mode,int treat,int waitconnect,char* xsend,char* adr,char* fil,htsblk* retour) {
  462.   //htsblk retour;
  463.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  464.   T_SOC soc=INVALID_SOCKET;
  465.   //char *p,*q;
  466.   
  467.   // retour prΘdΘfini: erreur
  468.   if (retour) {
  469.     retour->adr=NULL;
  470.     retour->size=0;
  471.     retour->msg[0]='\0';
  472.     retour->statuscode=-5;          // a priori erreur non fatale
  473.   }
  474.  
  475. #if HDEBUG
  476.   printf("adr=%s\nfichier=%s\n",adr,fil);
  477. #endif
  478.   
  479.   // ouvrir liaison
  480. #if HDEBUG
  481.   printf("CrΘation d'une socket sur %s\n",adr);
  482. #endif
  483.  
  484. #if CNXDEBUG
  485.   printf("..newhttp\n");
  486. #endif
  487.  
  488.   /* connexion */
  489.   if (retour) {
  490.     if ( (!(retour->req.proxy.active)) || (strcmp(adr,"file://")==0) ) {    /* pas de proxy, ou non utilisable ici */
  491.       soc=newhttp(adr,retour,-1,waitconnect);
  492.     } else {
  493.       soc=newhttp(retour->req.proxy.name,retour,retour->req.proxy.port,waitconnect);  // ouvrir sur le proxy α la place
  494.     }
  495.   } else {
  496.     soc=newhttp(adr,NULL,-1,waitconnect);    
  497.   }
  498.  
  499.   // copier index socket retour
  500.   if (retour) retour->soc=soc;
  501.  
  502.   /* Check for errors */
  503.   if (soc == INVALID_SOCKET) {
  504.     if (retour) {
  505.       if (retour->msg) {
  506.         if (!strnotempty(retour->msg)) {
  507.           strcpy(retour->msg,"Connect error");
  508.         }
  509.       }
  510.     }
  511.   }
  512.  
  513.   // --------------------
  514.   // court-circuit (court circuite aussi le proxy..)
  515.   // LOCAL_SOCKET_ID est une pseudo-socket locale
  516.   if (soc==LOCAL_SOCKET_ID) {
  517.     retour->is_file=1;  // fichier local
  518.     if (mode==0) {    // GET
  519.  
  520.       // Test en cas de file:///C|...
  521.       if (!fexist(fconv(unescape_http(fil))))
  522.         if (fexist(fconv(unescape_http(fil+1)))) {
  523.           char tempo[HTS_URLMAXSIZE*2];
  524.           strcpy(tempo,fil+1);
  525.           strcpy(fil,tempo);
  526.         }
  527.  
  528.       // Ouvrir
  529.       retour->totalsize=fsize(fconv(unescape_http(fil)));  // taille du fichier
  530.       retour->msg[0]='\0';
  531.       soc=INVALID_SOCKET;
  532.       if (retour->totalsize<0)
  533.         strcpy(retour->msg,"Unable to open file");
  534.       else if (retour->totalsize==0)
  535.         strcpy(retour->msg,"File empty");
  536.       else {
  537.         // Note: On passe par un FILE* (plus propre)
  538.         //soc=open(fil,O_RDONLY,0);    // en lecture seule!
  539.         retour->fp=fopen(fconv(unescape_http(fil)),"rb");  // ouvrir
  540.         if (retour->fp==NULL)
  541.           soc=INVALID_SOCKET;
  542.         else
  543.           soc=LOCAL_SOCKET_ID;
  544.       }
  545.       retour->soc=soc;
  546.       if (soc!=INVALID_SOCKET) {
  547.         retour->statuscode=200;   // OK
  548.         strcpy(retour->msg,"OK");
  549.         guess_httptype(retour->contenttype,fil);
  550.       } else if (strnotempty(retour->msg)==0)
  551.           strcpy(retour->msg,"Unable to open file");
  552.       return soc;  // renvoyer
  553.     } else {    // HEAD ou POST : interdit sur un local!!!! (c'est idiot!)
  554.       strcpy(retour->msg,"Unexpected Head/Post local request");
  555.       soc=INVALID_SOCKET;    // erreur
  556.       retour->soc=soc;
  557.       return soc;
  558.     }
  559.   } 
  560.   // --------------------
  561.  
  562.   if (soc!=INVALID_SOCKET) {    
  563.     char rcvd[1100];
  564.     rcvd[0]='\0';
  565. #if HDEBUG
  566.     printf("Ok, connexion rΘussie, id=%d\n",soc);
  567. #endif
  568.     
  569.     // connectΘ?
  570.     if (waitconnect) {
  571.       http_sendhead(NULL,mode,xsend,adr,fil,NULL,NULL,retour);
  572.     } 
  573.     
  574.     if (soc!=INVALID_SOCKET) {
  575.       
  576. #if HDEBUG
  577.       printf("Attente de la rΘponse:\n");
  578. #endif
  579.       
  580.       // si GET (rΘception d'un fichier), rΘceptionner en-tΩte d'abord,
  581.       // et ensuite le corps
  582.       // si POST on ne rΘceptionne rien du tout, c'est aprΦs que l'on fera
  583.       // une rΘception standard pour rΘcupΘrer l'en tΩte
  584.       if ((treat) && (waitconnect)) {  // traiter (attendre!) en-tΩte        
  585.         // RΘception de la status line et de l'en-tΩte (norme RFC1945)
  586.         
  587.         // status-line α rΘcupΘrer
  588.         finput(soc,rcvd,1024);
  589.         if (strnotempty(rcvd)==0)
  590.           finput(soc,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  591.  
  592.         // traiter status-line
  593.         treatfirstline(retour,rcvd);
  594.  
  595. #if HDEBUG
  596.         printf("Status-Code=%d\n",retour->statuscode);
  597. #endif
  598.         
  599.         // en-tΩte
  600.         
  601.         // header // ** !attention! HTTP/0.9 non supportΘ
  602.         do {
  603.           finput(soc,rcvd,1024);          
  604. #if HDEBUG
  605.           printf(">%s\n",rcvd);      
  606. #endif
  607.           if (strnotempty(rcvd))
  608.             treathead(NULL,NULL,NULL,retour,rcvd);  // traiter
  609.  
  610.         } while(strnotempty(rcvd));
  611.         
  612.         //rcvsize=-1;    // forCER CHARGEMENT INCONNU
  613.         
  614.         //if (retour)
  615.         //  retour->totalsize=rcvsize;
  616.         
  617.       } else { // si GET, on recevra l'en tΩte APRES
  618.         //rcvsize=-1;    // on ne connait pas la taille de l'en-tΩte
  619.         if (retour)
  620.           retour->totalsize=-1;
  621.       }
  622.       
  623.     }
  624.  
  625.   }
  626.     
  627.   return soc;
  628. }
  629.  
  630.  
  631. // envoi d'une requΦte
  632. int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char* referer_adr,char* referer_fil,htsblk* retour) {
  633.   char buff[8192];
  634.   //int use_11=0;     // HTTP 1.1 utilisΘ
  635.   int direct_url=0; // ne pas analyser l'url (exemple: ftp://)
  636.   char* search_tag=NULL;
  637.   buff[0]='\0';
  638.  
  639.   // header Date
  640.   //strcat(buff,"Date: ");
  641.   //time_gmt_rfc822(buff);    // obtenir l'heure au format rfc822
  642.   //sendc("\n");
  643.   //strcat(buff,buff);
  644.  
  645.   // possibilitΘ non documentΘe: >post: et >postfile:
  646.   // si prΘsence d'un tag >post: alors executer un POST
  647.   // exemple: http://www.someweb.com/test.cgi?foo>post:posteddata=10&foo=5
  648.   // si prΘsence d'un tag >postfile: alors envoyer en tΩte brut contenu dans le fichier en question
  649.   // exemple: http://www.someweb.com/test.cgi?foo>postfile:post0.txt
  650.   search_tag=strstr(fil,POSTTOK":");
  651.   if (!search_tag) {
  652.     search_tag=strstr(fil,POSTTOK"file:");
  653.     if (search_tag) {     // postfile
  654.       if (mode==0) {      // GET!
  655.         FILE* fp=fopen(unescape_http(search_tag+strlen(POSTTOK)+5),"rb");
  656.         if (fp) {
  657.           char line[1100];
  658.           char protocol[256],url[HTS_URLMAXSIZE*2],method[256];
  659.           linput(fp,line,1000);
  660.           if (sscanf(line,"%s %s %s",method,url,protocol) == 3) {
  661.             // selon que l'on a ou pas un proxy
  662.             if (retour->req.proxy.active)
  663.               sprintf(buff,"%s http://%s%s %s\r\n",method,adr,url,protocol);
  664.             else
  665.               sprintf(buff,"%s %s %s\r\n",method,url,protocol);
  666.             // lire le reste en brut
  667.             fread(buff+strlen(buff),8000-strlen(buff),1,fp);
  668.           }
  669.           fclose(fp);
  670.         }
  671.       }
  672.     }
  673.   }
  674.   // Fin postfile
  675.   
  676.   if (strnotempty(buff)==0) {    // PAS POSTFILE
  677.     // Type de requΦte?
  678.     if ((search_tag) && (mode==0)) {
  679.       strcat(buff,"POST ");
  680.     } else if (mode==0) {    // GET
  681.       strcat(buff,"GET ");
  682.     } else {  // if (mode==1) {
  683.       if (!retour->req.http11)        // forcer HTTP/1.0
  684.         strcat(buff,"GET ");      // certains serveurs (cgi) buggent avec HEAD
  685.       else
  686.         strcat(buff,"HEAD ");
  687.     }
  688.     
  689.     // si on gΦre un proxy, il faut une Absolute URI: on ajoute avant http://www.adr.dom
  690.     if (retour->req.proxy.active) {
  691.       if (!strfield(adr,"ftp://")) {
  692. #if HDEBUG
  693.         printf("Proxy Use: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  694. #endif
  695.         strcat(buff,"http://");
  696.         strcat(buff,jump_identification(adr));
  697.       } else {          // ftp:// en proxy http
  698. #if HDEBUG
  699.         printf("Proxy Use for ftp: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  700. #endif
  701.         direct_url=1;             // ne pas analyser user/pass
  702.         strcat(buff,adr);
  703.       }
  704.     } 
  705.     
  706.     // NOM DU FICHIER
  707.     // on slash doit Ωtre prΘsent en dΘbut, sinon attention aux bad request! (400)
  708.     if (*fil!='/') strcat(buff,"/");
  709.     {
  710.       char tempo[HTS_URLMAXSIZE*2];
  711.       tempo[0]='\0';
  712.       if (search_tag)
  713.         strncat(tempo,fil,(int) (search_tag - fil));
  714.       else
  715.         strcpy(tempo,fil);
  716.       escape_check_url(tempo);
  717.       strcat(buff,tempo);       // avec Θchappement
  718.     }
  719.     
  720.     // protocole
  721.     if (!retour->req.http11) {     // forcer HTTP/1.0
  722.       //use_11=0;
  723.       strcat(buff," HTTP/1.0\x0d\x0a");
  724.     } else {                   // RequΦte 1.1
  725.       //use_11=1;
  726.       strcat(buff," HTTP/1.1\x0d\x0a");
  727.     }
  728.  
  729.     /* supplemental data */
  730.     if (xsend) strcat(buff,xsend);    // Θventuelles autres lignes
  731.  
  732.     // tester proxy authentication
  733.     if (retour->req.proxy.active) {
  734.       char* a=jump_identification(retour->req.proxy.name);
  735.       if (a!=retour->req.proxy.name) {  // et hop, authentification proxy!
  736.         char autorisation[1100];
  737.         char user_pass[256];        
  738.         autorisation[0]=user_pass[0]='\0';
  739.         //
  740.         strncat(user_pass,retour->req.proxy.name,(int) (a - retour->req.proxy.name) - 1);
  741.         strcpy(user_pass,unescape_http(user_pass));
  742.         code64(user_pass,autorisation);
  743.         strcat(buff,"Proxy-Authorization: Basic ");
  744.         strcat(buff,autorisation);
  745.         strcat(buff,H_CRLF);
  746. #if HDEBUG
  747.         printf("Proxy-Authenticate, %s (code: %s)\n",user_pass,autorisation);
  748. #endif
  749.       }
  750.     }
  751.     
  752.     // Referer?
  753.     if ((referer_adr) && (referer_fil)) {       // existe
  754.       if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) {   // non vide
  755.         if (strcmp(referer_adr,"file://")) {      // PAS file://
  756.           strcat(buff,"Referer: ");
  757.           strcat(buff,"http://");
  758.           strcat(buff,jump_identification(referer_adr));
  759.           strcat(buff,referer_fil);
  760.           strcat(buff,H_CRLF);
  761.         }
  762.       }
  763.     }
  764.     
  765.     // POST?
  766.     if (mode==0) {      // GET!
  767.       if (search_tag) {
  768.         char clen[256];
  769.         sprintf(clen,"Content-length: %d"H_CRLF,(int)(strlen(unescape_http(search_tag+strlen(POSTTOK)+1))));
  770.         strcat(buff,clen);
  771.       }
  772.     }
  773.     
  774.     // gestion cookies?
  775.     if (cookie) {
  776.       char* b=cookie->data;
  777.       int cook=0;
  778.       int max_cookies=8;
  779.       int max_size=2048;
  780.       max_size+=strlen(buff);
  781.       do {
  782.         b=cookie_find(b,"",jump_identification(adr),fil);       // prochain cookie satisfaisant aux conditions
  783.         if (b) {
  784.           max_cookies--;
  785.           if (!cook) {
  786.             strcat(buff,"Cookie: ");
  787.             strcat(buff,"$Version=1; ");
  788.             cook=1;
  789.           } else
  790.             strcat(buff,"; ");
  791.           strcat(buff,cookie_get(b,5));
  792.           strcat(buff,"=");
  793.           strcat(buff,cookie_get(b,6));
  794.           strcat(buff,"; $Path=");
  795.           strcat(buff,cookie_get(b,2));
  796.           b=cookie_nextfield(b);
  797.         }
  798.       } while( (b) && (max_cookies>0) && ((int)strlen(buff)<max_size));
  799.       if (cook) {                           // on a envoyΘ un (ou plusieurs) cookie?
  800.         strcat(buff,H_CRLF);
  801. #if DEBUG_COOK
  802.         printf("Header:\n%s\n",buff);
  803. #endif
  804.       }
  805.     }
  806.     
  807.     // connection close?
  808.     //if (use_11)     // Si on envoie une requΦte 1.1, prΘciser qu'on ne veut pas de keep-alive!!
  809.     strcat(buff,"Connection: close"H_CRLF);
  810.     
  811.     // gΘrer le keep-alive (garder socket)
  812.     //strcat(buff,"Connection: Keep-Alive\n");
  813.     
  814.     {
  815.       char* real_adr=jump_identification(adr);
  816.       //if ((use_11) || (retour->user_agent_send)) {   // Pour le 1.1 on utilise un Host:
  817.       if (!direct_url) {     // pas ftp:// par exemple
  818.         //if (!retour->req.proxy.active) {
  819.         strcat(buff,"Host: "); strcat(buff,real_adr); strcat(buff,H_CRLF);
  820.         //}
  821.       }
  822.       //}
  823.  
  824.       // PrΘsence d'un user-agent?
  825.       if (retour->req.user_agent_send) {  // ohh un user-agent
  826.         char s[256];
  827.         // HyperTextSeeker/"HTSVERSION
  828.         sprintf(s,"User-Agent: %s"H_CRLF,retour->req.user_agent);
  829.         strcat(buff,s);
  830.         
  831.         // pour les serveurs difficiles
  832.         strcat(buff,"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/svg+xml, */*"H_CRLF);
  833.         if (strnotempty(retour->req.lang_iso)) {
  834.           strcat(buff,"Accept-Language: "); strcat(buff,retour->req.lang_iso); strcat(buff,H_CRLF);
  835.         }
  836.         strcat(buff,"Accept-Charset: iso-8859-1, *"H_CRLF);   
  837.         if (retour->req.http11) {
  838. #if HTS_USEZLIB
  839.           if ((!retour->req.range_used) && (!retour->req.nocompression))
  840.             strcat(buff,"Accept-Encoding: gzip, deflate, compress, identity"H_CRLF);
  841.           else
  842.             strcat(buff,"Accept-Encoding: identity"H_CRLF);       /* no compression */
  843. #else
  844.           strcat(buff,"Accept-Encoding: identity"H_CRLF);         /* no compression */
  845. #endif
  846.         }
  847.       } else {
  848.         strcat(buff,"Accept: */*"H_CRLF);         // le minimum
  849.       }
  850.  
  851.       /* Authentification */
  852.       {
  853.         char autorisation[1100];
  854.         char* a;
  855.         autorisation[0]='\0';
  856.         if (real_adr != adr) {  // ohh une authentification!
  857.           if (!direct_url) {      // pas ftp:// par exemple
  858.             char user_pass[256];
  859.             user_pass[0]='\0';
  860.             strncat(user_pass,adr,(int) (real_adr - adr) - 1);
  861.             strcpy(user_pass,unescape_http(user_pass));
  862.             code64(user_pass,autorisation);
  863.             if (strcmp(fil,"/robots.txt"))      /* pas robots.txt */
  864.               bauth_add(cookie,real_adr,fil,autorisation);
  865.           }
  866.         } else if ( (a=bauth_check(cookie,real_adr,fil)) )
  867.           strcpy(autorisation,a);
  868.         /* On a une autorisation a donner?  */
  869.         if (strnotempty(autorisation)) {
  870.           strcat(buff,"Authorization: Basic ");
  871.           strcat(buff,autorisation);
  872.           strcat(buff,H_CRLF);
  873.         }
  874.       }
  875.  
  876.     }
  877.     //strcat(buff,"Accept-Language: en\n");
  878.     //strcat(buff,"Accept-Charset: iso-8859-1,*,utf-8\n");
  879.     
  880.     // CRLF de fin d'en tΩte
  881.     strcat(buff,H_CRLF);
  882.     
  883.     // donnΘes complΘmentaires?
  884.     if (search_tag)
  885.     if (mode==0)      // GET!
  886.       strcat(buff,unescape_http(search_tag+strlen(POSTTOK)+1));
  887.   }
  888.   
  889. #if HDEBUG
  890. #endif
  891.   if (_DEBUG_HEAD) {
  892.     if (ioinfo) {
  893.       fprintf(ioinfo,"request for %s%s:\r\n",jump_identification(adr),fil);
  894.       fprintfio(ioinfo,buff,"<<< ");
  895.       fprintf(ioinfo,"\r\n");
  896.       fflush(ioinfo);
  897.     }
  898.   }  // Fin test pas postfile
  899.   //
  900.  
  901.   // Envoi
  902.   if (sendc(retour, buff)<0) {  // ERREUR, socket rompue?...
  903.   //if (sendc(retour->soc,buff) != strlen(buff)) {  // ERREUR, socket rompue?...
  904.     deletesoc_r(retour);  // fermer tout de mΩme
  905.     // et tenter de reconnecter
  906.     
  907.     strcpy(retour->msg,"Broken pipe");
  908.     retour->soc=INVALID_SOCKET;
  909.   }
  910.   
  911.   // RX'98
  912.   return 0;
  913. }
  914.  
  915.  
  916.  
  917.  
  918. // traiter 1ere ligne d'en tΩte
  919. void treatfirstline(htsblk* retour,char* rcvd) {
  920.   char* a=rcvd;
  921.   // exemple:
  922.   // HTTP/1.0 200 OK
  923.   if (*a) {
  924.     // note: certains serveurs buggΘs renvoient HTTP/1.0\n200 OK ou " HTTP/1.0 200 OK"
  925.     while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces au dΘbut
  926.     if (strfield(a, "HTTP/")) {
  927.       // sauter HTTP/1.x
  928.       while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  929.       if (*a != '\0') {
  930.         while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  931.         if ((*a>='0') && (*a<='9')) {
  932.           sscanf(a,"%d",&(retour->statuscode));
  933.           // sauter 200
  934.           while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  935.           while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  936.           if ((strlen(a) > 1) && (strlen(a) < 64) )                // message retour
  937.             strcpy(retour->msg,a);
  938.           else
  939.             infostatuscode(retour->msg,retour->statuscode);
  940.           // type MIME par dΘfaut
  941.           strcpy(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  942.         } else {  // pas de code!
  943.           retour->statuscode=-1;
  944.           strcpy(retour->msg,"Unknown response structure");
  945.         }
  946.       } else {  // euhh??
  947.         retour->statuscode=-1;
  948.         strcpy(retour->msg,"Unknown response structure");
  949.       }
  950.     } else {
  951.       if (strnotempty(a)) {
  952.         retour->statuscode=-1;
  953.         strcpy(retour->msg,"Unknown response structure, no HTTP/ response given");
  954.       } else {
  955.         /* This is dirty .. */
  956.         retour->statuscode=200;
  957.         strcpy(retour->msg, "Unknown, assuming junky server");
  958.         strcpy(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  959.       }
  960.     }
  961.   } else {  // vide!
  962.     /*
  963.     retour->statuscode=-1;
  964.     strcpy(retour->msg,"Empty reponse or internal error");
  965.     */
  966.     /* This is dirty .. */
  967.     retour->statuscode=200;
  968.     strcpy(retour->msg, "Unknown, assuming junky server");
  969.     strcpy(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  970.   }
  971. }
  972.  
  973. // traiter ligne par ligne l'en tΩte
  974. // gestion des cookies
  975. void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) {
  976.   int p;
  977.   if ((p=strfield(rcvd,"Content-length:"))!=0) {
  978. #if HDEBUG
  979.     printf("ok, Content-length: dΘtectΘ\n");
  980. #endif
  981.     sscanf(rcvd+p,LLintP,&(retour->totalsize));
  982.   }
  983.   else if ((p=strfield(rcvd,"Content-Disposition:"))!=0) {
  984.     while(*(rcvd+p)==' ') p++;    // sauter espaces
  985.     if ((int) strlen(rcvd+p)<250) { // pas trop long?
  986.       char tmp[256];
  987.       char *a=NULL,*b=NULL;
  988.       strcpy(tmp,rcvd+p);
  989.       a=strstr(tmp,"filename=");
  990.       if (a) {
  991.         a+=strlen("filename=");
  992.         while(is_space(*a)) a++;
  993.         //a=strchr(a,'"');
  994.         if (a) {
  995.           char *c=NULL;
  996.           //a++;      /* jump " */
  997.           while((c=strchr(a,'/')))    /* skip all / (see RFC2616) */
  998.             a=c+1;
  999.           //b=strchr(a+1,'"');
  1000.           b=a+strlen(a)-1;
  1001.           while(is_space(*b)) b--;
  1002.           b++;
  1003.           if (b) {
  1004.             *b='\0';
  1005.             if ((int) strlen(a) < 200) { // pas trop long?
  1006.               strcpy(retour->cdispo,a);
  1007.             }
  1008.           }
  1009.         }
  1010.       } 
  1011.     }
  1012.   }
  1013.   else if ((p=strfield(rcvd,"Last-Modified:"))!=0) {
  1014.     while(*(rcvd+p)==' ') p++;    // sauter espaces
  1015.     if ((int) strlen(rcvd+p)<64) { // pas trop long?
  1016.       //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  1017.       strcpy(retour->lastmodified,rcvd+p);
  1018.     }
  1019.   }
  1020.   else if ((p=strfield(rcvd,"Date:"))!=0) {
  1021.     if (strnotempty(retour->lastmodified)==0) {          /* pas encore de last-modified */
  1022.       while(*(rcvd+p)==' ') p++;    // sauter espaces
  1023.       if ((int) strlen(rcvd+p)<64) { // pas trop long?
  1024.         //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  1025.         strcpy(retour->lastmodified,rcvd+p);
  1026.       }
  1027.     }
  1028.   }
  1029.   else if ((p=strfield(rcvd,"Etag:"))!=0) {   /* Etag */
  1030.     if (retour) {
  1031.       while(*(rcvd+p)==' ') p++;    // sauter espaces
  1032.       if ((int) strlen(rcvd+p)<64)  // pas trop long?
  1033.         strcpy(retour->etag,rcvd+p);
  1034.       else    // erreur.. ignorer
  1035.         retour->etag[0]='\0';
  1036.     }
  1037.   }
  1038.   else if ((p=strfield(rcvd,"Transfer-Encoding: chunked"))!=0) {  // chunk!
  1039.     retour->is_chunk=1;     // chunked
  1040.     //retour->http11=2;     // chunked
  1041. #if HDEBUG
  1042.     printf("ok, Transfer-Encoding: dΘtectΘ\n");
  1043. #endif
  1044.   }
  1045.   else if ((p=strfield(rcvd,"Content-type:"))!=0) {
  1046.     if (retour) {
  1047.       char tempo[1100];
  1048.       // Θviter les text/html; charset=foo
  1049.       {
  1050.         char* a=strchr(rcvd+p,';');
  1051.         if (a) *a='\0';
  1052.       }
  1053.       sscanf(rcvd+p,"%s",tempo);
  1054.       if (strlen(tempo)<64)    // pas trop long!!
  1055.         strcpy(retour->contenttype,tempo);
  1056.       else
  1057.         strcpy(retour->contenttype,"application/octet-stream-unknown");    // erreur
  1058.     }
  1059.   }
  1060.   else if ((p=strfield(rcvd,"Content-Range:"))!=0) {
  1061.     char* a=strstr(rcvd+p,"*/");
  1062.     if (a) {
  1063.       if (sscanf(a+2,LLintP,&retour->crange) != 1) {
  1064.         retour->crange=0;
  1065.       }
  1066.     }
  1067.   }
  1068.   else if ((p=strfield(rcvd,"Content-Encoding:"))!=0) {
  1069.     if (retour) {
  1070.       char tempo[1100];
  1071.       {
  1072.         char* a=strchr(rcvd+p,';');
  1073.         if (a) *a='\0';
  1074.       }
  1075.       sscanf(rcvd+p,"%s",tempo);
  1076.       if (strlen(tempo)<64)    // pas trop long!!
  1077.         strcpy(retour->contentencoding,tempo);
  1078.       else
  1079.         retour->contentencoding[0]='\0';    // erreur
  1080. #if HTS_USEZLIB
  1081.       /* Check known encodings */
  1082.       if (retour->contentencoding[0]) {
  1083.         if (
  1084.           (strfield2(retour->contentencoding, "gzip"))
  1085.           || (strfield2(retour->contentencoding, "x-gzip"))
  1086.           /*
  1087.           || (strfield2(retour->contentencoding, "compress"))
  1088.           || (strfield2(retour->contentencoding, "x-compress"))
  1089.           */
  1090.           || (strfield2(retour->contentencoding, "deflate"))
  1091.           || (strfield2(retour->contentencoding, "x-deflate"))
  1092.           ) {
  1093.         retour->compressed=1;
  1094.         }
  1095.       }
  1096. #endif
  1097.     }
  1098.   }
  1099.   else if ((p=strfield(rcvd,"Location:"))!=0) {
  1100.     if (retour) {
  1101.       if (retour->location) {
  1102.         while(*(rcvd+p)==' ') p++;    // sauter espaces
  1103.         if ((int) strlen(rcvd+p)<HTS_URLMAXSIZE)  // pas trop long?
  1104.           strcpy(retour->location,rcvd+p);
  1105.         else    // erreur.. ignorer
  1106.           retour->location[0]='\0';
  1107.       }
  1108.     }
  1109.   }
  1110.   else if ((p=strfield(rcvd,"Connection: Keep-Alive"))!=0) {
  1111.     // non, pas de keep-alive! on dΘconnectera..          
  1112.   }
  1113.   else if ((p=strfield(rcvd,"Keep-Alive:"))!=0) {    // params keep-alive
  1114.     // rien α faire          
  1115.   }
  1116.   else if ( ((p=strfield(rcvd,"Set-Cookie:"))!=0) && (cookie) ) {    // ohh un cookie
  1117.     char* a = rcvd+p;           // pointeur
  1118.     char domain[256];           // domaine cookie (.netscape.com)
  1119.     char path[256];             // chemin (/)
  1120.     char cook_name[256];        // nom cookie (MYCOOK)
  1121.     char cook_value[8192];      // valeur (ID=toto,S=1234)
  1122. #if DEBUG_COOK
  1123.     printf("set-cookie detected\n");
  1124. #endif
  1125.     while(*a) {
  1126.       char *token_st,*token_end;
  1127.       char *value_st,*value_end;
  1128.       char name[256];
  1129.       char value[8192];
  1130.       int next=0;
  1131.       name[0]=value[0]='\0';
  1132.       //
  1133.  
  1134.       // initialiser cookie lu actuellement
  1135.       if (adr)
  1136.         strcpy(domain,jump_identification(adr));     // domaine
  1137.       strcpy(path,"/");         // chemin (/)
  1138.       strcpy(cook_name,"");     // nom cookie (MYCOOK)
  1139.       strcpy(cook_value,"");    // valeur (ID=toto,S=1234)
  1140.       // boucler jusqu'au prochain cookie ou la fin
  1141.       do {
  1142.         char* start_loop=a;
  1143.         while(is_space(*a)) a++;    // sauter espaces
  1144.         token_st=a;                 // dΘpart token
  1145.         while((!is_space(*a)) && (*a) && (*a!=';') && (*a!='=')) a++;    // arrΩter si espace, point virgule
  1146.         token_end=a;
  1147.         while(is_space(*a)) a++;    // sauter espaces
  1148.         if (*a=='=') {    // name=value
  1149.           a++;
  1150.           while(is_space(*a)) a++;    // sauter espaces
  1151.           value_st=a;
  1152.           while( (*a!=';') && (*a)) a++;    // prochain ;
  1153.           //while( ((*a!='"') || (*(a-1)=='\\')) && (*a)) a++;    // prochain " (et pas \")
  1154.           value_end=a;
  1155.           //if (*a==';') {  // finit par un ;
  1156.           // vΘrifier dΘbordements
  1157.           if ( (((int) (token_end - token_st))<200) && (((int) (value_end - value_st))<8000)
  1158.             && (((int) (token_end - token_st))>0)   && (((int) (value_end - value_st))>0) ) {
  1159.             name[0]='\0';
  1160.             value[0]='\0';
  1161.             strncat(name,token_st,(int) (token_end - token_st));
  1162.             strncat(value,value_st,(int) (value_end - value_st));
  1163. #if DEBUG_COOK
  1164.             printf("detected cookie-av: name=\"%s\" value=\"%s\"\n",name,value);
  1165. #endif
  1166.             if (strfield2(name,"domain")) {
  1167.               strcpy(domain,value);
  1168.             }
  1169.             else if (strfield2(name,"path")) {
  1170.               strcpy(path,value);
  1171.             }
  1172.             else if (strfield2(name,"max-age")) {
  1173.               // ignorΘ..
  1174.             }
  1175.             else if (strfield2(name,"expires")) {
  1176.               // ignorΘ..
  1177.             }
  1178.             else if (strfield2(name,"version")) {
  1179.               // ignorΘ..
  1180.             }
  1181.             else if (strfield2(name,"comment")) {
  1182.               // ignorΘ
  1183.             }
  1184.             else if (strfield2(name,"secure")) {    // ne devrait pas arriver ici
  1185.               // ignorΘ
  1186.             }
  1187.             else {
  1188.               if (strnotempty(cook_name)==0) {          // noter premier: nom et valeur cookie
  1189.                 strcpy(cook_name,name);
  1190.                 strcpy(cook_value,value);
  1191.               } else {                             // prochain cookie
  1192.                 a=start_loop;      // on devra recommencer α cette position
  1193.                 next=1;            // enregistrer
  1194.               }
  1195.             }
  1196.           }
  1197.         }
  1198.         if (!next) {
  1199.           while((*a!=';') && (*a)) a++;    // prochain
  1200.           while(*a==';') a++;             // sauter ;
  1201.         }
  1202.       } while((*a) && (!next));
  1203.       if (strnotempty(cook_name)) {          // cookie?
  1204. #if DEBUG_COOK
  1205.         printf("new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",cook_name,cook_value,domain,path);
  1206. #endif
  1207.         cookie_add(cookie,cook_name,cook_value,domain,path);
  1208.       }
  1209.     }
  1210.   }
  1211. }
  1212.  
  1213.  
  1214. // transforme le message statuscode en chaεne
  1215. void infostatuscode(char* msg,int statuscode) {
  1216.   switch( statuscode) {    
  1217.     // Erreurs HTTP, selon RFC
  1218.   case 100: strcpy( msg,"Continue"); break; 
  1219.   case 101: strcpy( msg,"Switching Protocols"); break; 
  1220.   case 200: strcpy( msg,"OK"); break; 
  1221.   case 201: strcpy( msg,"Created"); break; 
  1222.   case 202: strcpy( msg,"Accepted"); break; 
  1223.   case 203: strcpy( msg,"Non-Authoritative Information"); break; 
  1224.   case 204: strcpy( msg,"No Content"); break; 
  1225.   case 205: strcpy( msg,"Reset Content"); break; 
  1226.   case 206: strcpy( msg,"Partial Content"); break; 
  1227.   case 300: strcpy( msg,"Multiple Choices"); break; 
  1228.   case 301: strcpy( msg,"Moved Permanently"); break; 
  1229.   case 302: strcpy( msg,"Moved Temporarily"); break; 
  1230.   case 303: strcpy( msg,"See Other"); break; 
  1231.   case 304: strcpy( msg,"Not Modified"); break; 
  1232.   case 305: strcpy( msg,"Use Proxy"); break; 
  1233.   case 306: strcpy( msg,"Undefined 306 error"); break; 
  1234.   case 307: strcpy( msg,"Temporary Redirect"); break; 
  1235.   case 400: strcpy( msg,"Bad Request"); break; 
  1236.   case 401: strcpy( msg,"Unauthorized"); break; 
  1237.   case 402: strcpy( msg,"Payment Required"); break; 
  1238.   case 403: strcpy( msg,"Forbidden"); break; 
  1239.   case 404: strcpy( msg,"Not Found"); break; 
  1240.   case 405: strcpy( msg,"Method Not Allowed"); break; 
  1241.   case 406: strcpy( msg,"Not Acceptable"); break; 
  1242.   case 407: strcpy( msg,"Proxy Authentication Required"); break; 
  1243.   case 408: strcpy( msg,"Request Time-out"); break; 
  1244.   case 409: strcpy( msg,"Conflict"); break; 
  1245.   case 410: strcpy( msg,"Gone"); break; 
  1246.   case 411: strcpy( msg,"Length Required"); break; 
  1247.   case 412: strcpy( msg,"Precondition Failed"); break; 
  1248.   case 413: strcpy( msg,"Request Entity Too Large"); break; 
  1249.   case 414: strcpy( msg,"Request-URI Too Large"); break; 
  1250.   case 415: strcpy( msg,"Unsupported Media Type"); break; 
  1251.   case 416: strcpy( msg,"Requested Range Not Satisfiable"); break; 
  1252.   case 417: strcpy( msg,"Expectation Failed"); break; 
  1253.   case 500: strcpy( msg,"Internal Server Error"); break; 
  1254.   case 501: strcpy( msg,"Not Implemented"); break; 
  1255.   case 502: strcpy( msg,"Bad Gateway"); break; 
  1256.   case 503: strcpy( msg,"Service Unavailable"); break; 
  1257.   case 504: strcpy( msg,"Gateway Time-out"); break; 
  1258.   case 505: strcpy( msg,"HTTP Version Not Supported"); break; 
  1259.     //
  1260.   default: if (strnotempty(msg)==0) strcpy( msg,"Unknown error"); break;
  1261.   }
  1262. }
  1263.  
  1264.  
  1265. // identique au prΘcΘdent, sauf que l'on donne adr+fil et non url complΦte
  1266. htsblk xhttpget(char* adr,char* fil) {
  1267.   T_SOC soc;
  1268.   htsblk retour;
  1269.   
  1270.   memset(&retour, 0, sizeof(htsblk));
  1271.   soc=http_fopen(adr,fil,&retour);
  1272.  
  1273.   if (soc!=INVALID_SOCKET) {
  1274.     http_fread(soc,&retour);
  1275. #if HTS_DEBUG_CLOSESOCK
  1276.     DEBUG_W("xhttpget: deletehttp\n");
  1277. #endif
  1278.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1279.     retour.soc=INVALID_SOCKET;
  1280.   }
  1281.   return retour;
  1282. }
  1283.  
  1284. // variation sur un thΦme...
  1285. // rΘceptionne uniquement un en-tΩte (HEAD)
  1286. // retourne dans xx.adr l'adresse pointant sur le bloc de mΘmoire de l'en tΩte
  1287. htsblk http_gethead(char* adr,char* fil) {
  1288.   T_SOC soc;
  1289.   htsblk retour;
  1290.  
  1291.   memset(&retour, 0, sizeof(htsblk));
  1292.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // HEAD, pas de traitement en-tΩte
  1293.  
  1294.   if (soc!=INVALID_SOCKET) {
  1295.     http_fread(soc,&retour);    // rΘception en-tΩte
  1296. #if HTS_DEBUG_CLOSESOCK
  1297.     DEBUG_W("http_gethead: deletehttp\n");
  1298. #endif
  1299.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1300.     retour.soc=INVALID_SOCKET;
  1301.   }
  1302.   return retour;
  1303. }
  1304. // oui ca ressemble vachement α xhttpget - en Θtant sobre on peut voir LA diffΘrence..
  1305.  
  1306.  
  1307. // lecture sur une socket ouverte, le header a dΘja ΘtΘ envoyΘ dans le cas de GET
  1308. // il ne reste plus qu'α lire les donnΘes
  1309. // (pour HEAD le header est lu ici!)
  1310. void http_fread(T_SOC soc,htsblk* retour) {  
  1311.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1312.   
  1313.   if (retour) retour->soc=soc;
  1314.   if (soc!=INVALID_SOCKET) {    
  1315.     // fonction de lecture d'une socket (plus propre)
  1316.     while(http_fread1(retour)!=-1);
  1317.     soc=retour->soc;
  1318.     if (retour->adr==NULL) {
  1319.       if (strnotempty(retour->msg)==0)
  1320.         sprintf(retour->msg,"Unable to read");
  1321.       return ;    // erreur
  1322.     } 
  1323.     
  1324. #if HDEBUG
  1325.     printf("Ok, donnΘes reτues\n");
  1326. #endif   
  1327.  
  1328.     return ;
  1329.     
  1330.   } 
  1331.   
  1332.   return ;
  1333. }
  1334.  
  1335. // check if data is available
  1336. int check_readinput(htsblk* r) {
  1337.   if (r->soc != INVALID_SOCKET) {
  1338.     fd_set fds;           // poll structures
  1339.     struct timeval tv;          // structure for select
  1340.     FD_ZERO(&fds);
  1341.     FD_SET(r->soc,&fds);           
  1342.     tv.tv_sec=0;
  1343.     tv.tv_usec=0;
  1344.     select(r->soc + 1,&fds,NULL,NULL,&tv);
  1345.     if (FD_ISSET(r->soc,&fds))
  1346.       return 1;
  1347.     else
  1348.       return 0;
  1349.   } else
  1350.     return 0;
  1351. }
  1352.  
  1353. // lecture d'un bloc sur une socket (ou un fichier!)
  1354. // >=0 : nombre d'octets lus
  1355. // <0 : fin ou erreur
  1356. HTS_INLINE LLint http_fread1(htsblk* r) {
  1357.   //int bufl=TAILLE_BUFFER;  // taille d'un buffer max.
  1358.   return http_xfread1(r,TAILLE_BUFFER);
  1359. }
  1360.  
  1361. // idem, sauf qu'ici on peut choisir la taille max de donnΘes α recevoir
  1362. // SI bufl==0 alors le buffer est censΘ Ωtre de 8kos, et on recoit par bloc de lignes
  1363. // en Θliminant les cr (ex: header), arrΩt si double-lf
  1364. // SI bufl==-1 alors le buffer est censΘ Ωtre de 8kos, et on recoit ligne par ligne
  1365. // en Θliminant les cr (ex: header), arrΩt si double-lf
  1366. // Note: les +1 dans les malloc sont d√s α l'octet nul rajoutΘ en fin de fichier
  1367. LLint http_xfread1(htsblk* r,int bufl) {
  1368.   int nl=-1;
  1369.  
  1370.   if (bufl>0) {
  1371.     if (!r->is_write) {     // stocker en mΘmoire
  1372.       if (r->totalsize>0) {    // totalsize dΘterminΘ ET ALLOUE
  1373.         if (r->adr==NULL) {
  1374.           r->adr=(char*) malloct((INTsys) r->totalsize + 1);
  1375.           r->size=0;
  1376.         }
  1377.         if (r->adr!=NULL) {
  1378.           // lecture
  1379.           nl = hts_read(r,r->adr + ((int) r->size),(int) (r->totalsize-r->size) );     /* NO 32 bit overlow possible here (no 4GB html!) */
  1380.           // nouvelle taille
  1381.           if (nl >= 0) r->size+=nl;
  1382.           
  1383.           if ((nl < 0) || (r->size >= r->totalsize))
  1384.             nl=-1;  // break
  1385.           
  1386.           r->adr[r->size]='\0';    // caractΦre NULL en fin au cas o∙ l'on traite des HTML
  1387.         }
  1388.         
  1389.       } else {                 // inconnu..
  1390.         // rΘserver de la mΘmoire?
  1391.         if (r->adr==NULL) {
  1392. #if HDEBUG
  1393.           printf("..alloc xfread\n");
  1394. #endif
  1395.           r->adr=(char*) malloct(bufl + 1);
  1396.           r->size=0;
  1397.         }
  1398.         else {
  1399. #if HDEBUG
  1400.           printf("..realloc xfread1\n");
  1401. #endif
  1402.           r->adr=(char*) realloct(r->adr,(int)r->size+bufl + 1);
  1403.         }
  1404.         
  1405.         if (r->adr!=NULL) {
  1406.           // lecture
  1407.           nl = hts_read(r,r->adr+(int)r->size,bufl);
  1408.           if (nl>0) {
  1409.             // resize
  1410.             r->adr=(char*) realloct(r->adr,(int)r->size+nl + 1);
  1411.             // nouvelle taille
  1412.             r->size+=nl;
  1413.             // octet nul
  1414.             if (r->adr) r->adr[r->size]='\0';
  1415.  
  1416.           } // sinon on a fini
  1417. #if HDEBUG
  1418.           else if (nl < 0)
  1419.             printf("..end read (%d)\n", nl);
  1420. #endif
  1421.         }
  1422. #if HDEBUG
  1423.         else printf("..-> error\n");
  1424. #endif
  1425.       }
  1426.  
  1427.       // pas de adr=erreur
  1428.       if (r->adr==NULL) nl=-1;
  1429.  
  1430.     } else {    // stocker sur disque
  1431.       char* buff;
  1432.       buff=(char*) malloct(bufl);
  1433.       if (buff!=NULL) {
  1434.         // lecture
  1435.         nl = hts_read(r,buff,bufl);
  1436.         // nouvelle taille
  1437.         if (nl > 0) { 
  1438.           r->size+=nl;
  1439.           if ((int) fwrite(buff,1,nl,r->out)!=nl) {
  1440.             r->statuscode=-1;
  1441.             strcpy(r->msg,"Write error on disk");
  1442.             nl=-1;
  1443.           }
  1444.         }
  1445.  
  1446.         if ((nl < 0) || ((r->totalsize>0) && (r->size >= r->totalsize)))
  1447.           nl=-1;  // break
  1448.  
  1449.         // libΘrer bloc tempo
  1450.         freet(buff);
  1451.       } else
  1452.         nl=-1;
  1453.       
  1454.       if ((nl < 0) && (r->out!=NULL)) {
  1455.         fflush(r->out); 
  1456.       }
  1457.         
  1458.         
  1459.     } // stockage disque ou mΘmoire
  1460.  
  1461.   } else {    // rΘception d'un en-tΩte octet par octet
  1462.     int count=256;
  1463.     int tot_nl=0;
  1464.     int lf_detected=0;
  1465.     int at_begining=1;
  1466.     do {
  1467.       nl=-1;
  1468.       count--;
  1469.       if (r->adr==NULL) {
  1470.         r->adr=(char*) malloct(8192);
  1471.         r->size=0;
  1472.       }
  1473.       if (r->adr!=NULL) {
  1474.         if (r->size < 8190) {
  1475.           // lecture
  1476.           nl = hts_read(r,r->adr+r->size,1);
  1477.           if (nl>0) {
  1478.             // exit if:
  1479.             // lf detected AND already detected before
  1480.             // or
  1481.             // lf detected AND first character read
  1482.             if (*(r->adr+r->size) == 10) {
  1483.               if (lf_detected || (at_begining) || (bufl<0))
  1484.                 count=-1;
  1485.               lf_detected=1;
  1486.             }
  1487.             if (*(r->adr+r->size) != 13) {   // sauter caractΦres 13
  1488.               if (
  1489.                 (*(r->adr+r->size) != 10)
  1490.                 &&
  1491.                 (*(r->adr+r->size) != 13)
  1492.                 ) {
  1493.                 // restart for new line
  1494.                 lf_detected=0;
  1495.               }
  1496.               (r->size)++;
  1497.               at_begining=0;
  1498.             }
  1499.             *(r->adr+r->size)='\0';    // terminer par octet nul
  1500.           }
  1501.         }
  1502.       }
  1503.       if (nl >= 0) {
  1504.         tot_nl+=nl;
  1505.         if (!check_readinput(r))
  1506.           count=-1;
  1507.       }
  1508.     } while((nl >= 0) && (count>0));
  1509.     nl = tot_nl;
  1510.   }
  1511. #if HDEBUG
  1512.   //printf("add to %d / %d\n",r->size,r->totalsize);
  1513. #endif
  1514.   // nl == 0 may mean "no relevant data", for example is using cache or ssl
  1515. #if HTS_USEOPENSSL
  1516.   if (r->ssl)
  1517.     return nl;
  1518.   else
  1519. #endif
  1520.     return ((nl > 0) ? nl : -1);        // ==0 is fatal if direct read
  1521. }
  1522.  
  1523.  
  1524. // teste une adresse, et suit l'Θventuel chemin "moved"
  1525. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1526. // copie dans loc la vΘritable adresse si celle-ci est diffΘrente
  1527. htsblk http_location(char* adr,char* fil,char* loc) {
  1528.   htsblk retour;
  1529.   int retry=0;
  1530.   int tryagain;
  1531.   // note: "RFC says"
  1532.   // 5 boucles au plus, on en teste au plus 8 ici
  1533.   // sinon abandon..
  1534.   do {
  1535.     tryagain=0;
  1536.     switch ((retour=http_test(adr,fil,loc)).statuscode) {
  1537.     case 200: break;   // ok!
  1538.     case 301: case 302: case 303: case 307: // moved!
  1539.       // recalculer adr et fil!
  1540.       if (ident_url_absolute(loc,adr,fil)!=-1) {
  1541.         tryagain=1;  // retenter
  1542.         retry++;     // ..encore une fois
  1543.       }
  1544.     }
  1545.   } while((tryagain) && (retry<5+3));
  1546.   return retour;
  1547. }
  1548.  
  1549.  
  1550. // teste si une URL (validitΘ, header, taille)
  1551. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1552. // en cas de moved xx, dans location
  1553. // abandonne dΘsormais au bout de 30 secondes (aurevoir les sites
  1554. // qui nous font poireauter 5 heures..) -> -2=timeout
  1555. htsblk http_test(char* adr,char* fil,char* loc) {
  1556.   T_SOC soc;
  1557.   htsblk retour;
  1558.   //int rcvsize=-1;
  1559.   //char* rcv=NULL;    // adresse de retour
  1560.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1561.   TStamp tl;
  1562.   int timeout=30;  // timeout pour un check (arbitraire) // **
  1563.  
  1564.   // pour abandonner un site trop lent
  1565.   tl=time_local();
  1566.  
  1567.   loc[0]='\0';
  1568.   memset(&retour, 0, sizeof(htsblk));    // effacer
  1569.   retour.location=loc;    // si non nul, contiendra l'adresse vΘritable en cas de moved xx
  1570.  
  1571.   //soc=http_fopen(adr,fil,&retour,NULL);  // ouvrir, + header
  1572.  
  1573.   // on ouvre en head, et on traite l'en tΩte
  1574.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // ouvrir HEAD, + envoi header
  1575.   
  1576.   if (soc!=INVALID_SOCKET) {
  1577.     int e=0;
  1578.     // tant qu'on a des donnΘes, et qu'on ne recoit pas deux LF, et que le timeout n'arrie pas
  1579.     do {
  1580.       if (http_xfread1(&retour,0) < 0)
  1581.         e=1;
  1582.       else {
  1583.         if (retour.adr!=NULL) {
  1584.           if ((retour.adr[retour.size-1]!=10) || (retour.adr[retour.size-2]!=10))
  1585.             e=1;
  1586.         }
  1587.       }
  1588.             
  1589.       if (!e) {
  1590.         if ((time_local()-tl)>=timeout) {
  1591.           e=-1;
  1592.         }
  1593.       }
  1594.       
  1595.     } while (!e);
  1596.     
  1597.     if (e==1) {
  1598.       if (adr!=NULL) {
  1599.         int ptr=0;
  1600.         char rcvd[1100];
  1601.  
  1602.         // note: en gros recopie du traitement de back_wait()
  1603.         //
  1604.  
  1605.  
  1606.         // ----------------------------------------
  1607.         // traiter en-tΩte!
  1608.         // status-line α rΘcupΘrer
  1609.         ptr+=binput(retour.adr+ptr,rcvd,1024);
  1610.         if (strnotempty(rcvd)==0)
  1611.           ptr+=binput(retour.adr+ptr,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  1612.         
  1613.         // traiter status-line
  1614.         treatfirstline(&retour,rcvd);
  1615.         
  1616. #if HDEBUG
  1617.         printf("(Buffer) Status-Code=%d\n",retour.statuscode);
  1618. #endif
  1619.         
  1620.         // en-tΩte
  1621.         
  1622.         // header // ** !attention! HTTP/0.9 non supportΘ
  1623.         do {
  1624.           ptr+=binput(retour.adr+ptr,rcvd,1024);          
  1625. #if HDEBUG
  1626.           printf("(buffer)>%s\n",rcvd);      
  1627. #endif
  1628.           if (strnotempty(rcvd))
  1629.             treathead(NULL,NULL,NULL,&retour,rcvd);  // traiter
  1630.           
  1631.         } while(strnotempty(rcvd));
  1632.         // ----------------------------------------                    
  1633.         
  1634.         // libΘrer mΘmoire
  1635.         if (retour.adr!=NULL) { freet(retour.adr); retour.adr=NULL; }
  1636.       }
  1637.     } else {
  1638.       retour.statuscode=-2;
  1639.       strcpy(retour.msg,"Timeout While Testing");
  1640.     }
  1641.     
  1642.     
  1643. #if HTS_DEBUG_CLOSESOCK
  1644.     DEBUG_W("http_test: deletehttp\n");
  1645. #endif
  1646.     deletehttp(&retour);
  1647.     retour.soc=INVALID_SOCKET;
  1648.   }
  1649.   return retour;    
  1650. }
  1651.  
  1652. // CrΘe un lien (http) vers une adresse internet iadr
  1653. // retour: structure (adresse, taille, message si erreur (si !adr))
  1654. // peut ouvrir avec des connect() non bloquants: waitconnect=0/1
  1655. int newhttp(char* _iadr,htsblk* retour,int port,int waitconnect) {  
  1656.   t_fullhostent fullhostent_buffer;    // buffer pour resolver
  1657.   T_SOC soc;                           // descipteur de la socket
  1658.   char* iadr;
  1659.   // unsigned short int port;
  1660.   
  1661.   // tester un Θventuel id:pass et virer id:pass@ si dΘtectΘ
  1662.   iadr = jump_identification(_iadr);
  1663.   
  1664.   // si iadr="#" alors c'est une fausse URL, mais un vrai fichier
  1665.   // local.
  1666.   // utile pour les tests!
  1667.   //## if (iadr[0]!=lOCAL_CHAR) {
  1668.   if (strcmp(iadr,"file://")) {           /* non fichier */
  1669.     SOCaddr server;
  1670.     int server_size=sizeof(server);
  1671.     t_hostent* hp;    
  1672.     // effacer structure
  1673.     memset(&server, 0, sizeof(server));
  1674.  
  1675. #if HDEBUG
  1676.     printf("gethostbyname\n");
  1677. #endif
  1678.     
  1679.     // tester un Θventuel port
  1680.     if (port==-1) {
  1681.       char *a=jump_toport(iadr);
  1682. #if HTS_USEOPENSSL
  1683.       if (retour->ssl)
  1684.         port=443;
  1685.       else
  1686.         port=80;    // port par dΘfaut
  1687. #else
  1688.       port=80;    // port par dΘfaut
  1689. #endif
  1690.       if (a) {
  1691.         char iadr2[HTS_URLMAXSIZE*2];
  1692.         int i=-1;
  1693.         iadr2[0]='\0';
  1694.         sscanf(a+1,"%d",&i);
  1695.         if (i!=-1) {
  1696.           port=(unsigned short int) i;
  1697.         }
  1698.         
  1699.         // adresse vΘritable (sans :xx)
  1700.         strncat(iadr2,iadr,(int) (a - iadr));
  1701.  
  1702.         // adresse sans le :xx
  1703.         hp = hts_gethostbyname(iadr2, &fullhostent_buffer);
  1704.         
  1705.       } else {
  1706.  
  1707.         // adresse normale (port par dΘfaut par la suite)
  1708.         hp = hts_gethostbyname(iadr, &fullhostent_buffer);
  1709.         
  1710.       }
  1711.       
  1712.     } else    // port dΘfini
  1713.       hp = hts_gethostbyname(iadr, &fullhostent_buffer);
  1714.  
  1715.     
  1716.     // Conversion iadr -> adresse
  1717.     // structure recevant le nom de l'h⌠te, etc
  1718.     //struct     hostent     *hp;
  1719.     if (hp == NULL) {
  1720. #if DEBUG
  1721.       printf("erreur gethostbyname\n");
  1722. #endif
  1723.       if (retour)
  1724.       if (retour->msg)
  1725.         strcpy(retour->msg,"Unable to get server's address");
  1726.       return INVALID_SOCKET;
  1727.     }  
  1728.     // copie adresse
  1729.     SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  1730.     // memcpy(&SOCaddr_sinaddr(server), hp->h_addr_list[0], hp->h_length);
  1731.      
  1732.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  1733. #if HDEBUG
  1734.     printf("socket\n");
  1735. #endif
  1736. #if HTS_WIDE_DEBUG    
  1737.     DEBUG_W("socket\n");
  1738. #endif
  1739.     soc=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  1740. #if HTS_WIDE_DEBUG    
  1741.     DEBUG_W("socket done\n");
  1742. #endif
  1743.     if (soc==INVALID_SOCKET) {
  1744.       if (retour)
  1745.       if (retour->msg)
  1746.         strcpy(retour->msg,"Unable to create a socket");
  1747.       return INVALID_SOCKET;                        // erreur crΘation socket impossible
  1748.     }
  1749.     // structure: connexion au domaine internet, port 80 (ou autre)
  1750.     SOCaddr_initport(server, port);
  1751. #if HDEBUG
  1752.     printf("==%d\n",soc);
  1753. #endif
  1754.  
  1755.     // connexion non bloquante?
  1756.     if (!waitconnect ) {
  1757.       unsigned long p=1;  // non bloquant
  1758. #if HTS_WIN
  1759.       ioctlsocket(soc,FIONBIO,&p);
  1760. #else
  1761.       ioctl(soc,FIONBIO,&p);
  1762. #endif
  1763.     }
  1764.     
  1765.     // Connexion au serveur lui mΩme
  1766. #if HDEBUG
  1767.     printf("connect\n");
  1768. #endif
  1769.     
  1770. #if HTS_WIDE_DEBUG
  1771.     DEBUG_W("connect\n");
  1772. #endif
  1773. #if HTS_WIN
  1774.     if (connect(soc, (const struct sockaddr FAR *)&server, server_size) != 0) {
  1775. #else
  1776.       if (connect(soc, (struct sockaddr *)&server, server_size) == -1) {
  1777. #endif
  1778.  
  1779.         // no - non blocking
  1780.         //deletesoc(soc);
  1781.         //soc=INVALID_SOCKET;
  1782.  
  1783.         // bloquant
  1784.         if (waitconnect) {
  1785. #if HDEBUG
  1786.           printf("unable to connect!\n");
  1787. #endif
  1788.           if (retour)
  1789.           if (retour->msg)
  1790.             strcpy(retour->msg,"Unable to connect to the server");
  1791.           /* Close the socket and notify the error!!! */
  1792.           deletesoc(soc);
  1793.           return INVALID_SOCKET;
  1794.         }
  1795.       }
  1796. #if HTS_WIDE_DEBUG    
  1797.       DEBUG_W("connect done\n");
  1798. #endif
  1799.       
  1800. #if HDEBUG
  1801.       printf("connexion Θtablie\n");
  1802. #endif
  1803.     
  1804.     // A partir de maintenant, on peut envoyer et recevoir des donnΘes
  1805.     // via le flot identifiΘ par soc (socket): write(soc,adr,taille) et 
  1806.     // read(soc,adr,taille)
  1807.  
  1808.   } else {    // on doit ouvrir un fichier local!
  1809.     // il sera gΘrΘ de la mΩme maniΦre qu'une socket (c'est idem!)
  1810.  
  1811.     soc=LOCAL_SOCKET_ID;    // pseudo-socket locale..
  1812.     // soc sera remplacΘ lors d'un http_fopen() par un handle vΘritable!
  1813.  
  1814.   }   // teste fichier local ou http
  1815.   
  1816.   return soc;
  1817. }
  1818.  
  1819.  
  1820.  
  1821. // couper http://www.truc.fr/pub/index.html -> www.truc.fr /pub/index.html
  1822. // retour=-1 si erreur.
  1823. // si file://... alors adresse=file:// (et coupe le ?query dans ce cas)
  1824. int ident_url_absolute(char* url,char* adr,char* fil) {
  1825.   int pos=0;
  1826.   int scheme=0;
  1827.  
  1828.   // effacer adr et fil
  1829.   adr[0]=fil[0]='\0';
  1830.   
  1831. #if HDEBUG
  1832.   printf("protocol: %s\n",url);
  1833. #endif
  1834.  
  1835.   // Scheme?
  1836.   {
  1837.     char* a=url;
  1838.     while (isalpha((unsigned char)*a))
  1839.       a++;
  1840.     if (*a == ':')
  1841.       scheme=1;
  1842.   }
  1843.  
  1844.   // 1. optional scheme ":"
  1845.   if ((pos=strfield(url,"file:"))) {    // fichier local!! (pour les tests)
  1846.     //!! p+=3;
  1847.     strcpy(adr,"file://");
  1848.   } else if ((pos=strfield(url,"http:"))) {    // HTTP
  1849.     //!!p+=3;
  1850.   } else if ((pos=strfield(url,"ftp:"))) {    // FTP
  1851.     strcpy(adr,"ftp://");    // FTP!!
  1852.     //!!p+=3;
  1853. #if HTS_USEOPENSSL
  1854.   } else if ((pos=strfield(url,"https:"))) {    // HTTPS
  1855.     strcpy(adr,"https://");
  1856. #endif
  1857.   } else if (scheme) {
  1858.     return -1;    // erreur non reconnu
  1859.   } else
  1860.     pos=0;
  1861.  
  1862.   // 2. optional "//" authority
  1863.   if (strncmp(url+pos,"//",2)==0)
  1864.     pos+=2;
  1865.  
  1866.   // (url+pos) now points to the path (not net path)
  1867.  
  1868.   //## if (adr[0]!=lOCAL_CHAR) {    // adresse normale http
  1869.   if (!strfield(adr,"file:")) {      // PAS file://
  1870.     char *p,*q;
  1871.     p=url+pos;
  1872.  
  1873.     // p pointe sur le dΘbut de l'adresse, ex: www.truc.fr/sommaire/index.html
  1874.     q=strchr(jump_identification(p),'/');
  1875.     if (q==0) q=strchr(jump_identification(p),'?');     // http://www.foo.com?bar=1
  1876.     if (q==0) q=p+strlen(p);  // pointe sur \0
  1877.     // q pointe sur le chemin, ex: index.html?query=recherche
  1878.     
  1879.     // chemin www... trop long!!
  1880.     if ( ( ((int) (q - p)) )  > HTS_URLMAXSIZE) {
  1881.       //strcpy(retour.msg,"Path too long");
  1882.       return -1;    // erreur
  1883.     }
  1884.     
  1885.     // recopier adresse www..
  1886.     strncat(adr,p, ((int) (q - p)) );
  1887.     // *( adr+( ((int) q) - ((int) p) ) )=0;  // faut arrΩter la fumette!
  1888.     // recopier chemin /pub/..
  1889.     if (q[0] != '/')    // page par dΘfaut (/)
  1890.       strcat(fil,"/");
  1891.     strcat(fil,q);
  1892.     // SECURITE:
  1893.     // simplifier url pour les ../
  1894.     fil_simplifie(fil);
  1895.   } else {    // localhost file://
  1896.     char *p;
  1897.     int i;
  1898.     char* a;
  1899.  
  1900.     p=url+pos;
  1901.     
  1902.     strcat(fil,p);    // fichier local ; adr="#"
  1903.     a=strchr(fil,'?');
  1904.     if (a) 
  1905.       *a='\0';      /* couper query (inutile pour file:// lors de la requΩte) */
  1906.     // filtrer les \\ -> / pour les fichiers DOS
  1907.     for(i=0;i<(int) strlen(fil);i++)
  1908.       if (fil[i]=='\\')
  1909.         fil[i]='/';
  1910.   }
  1911.  
  1912.   // no hostname
  1913.   if (!strnotempty(adr))
  1914.     return -1;    // erreur non reconnu
  1915.  
  1916.   // nommer au besoin.. (non utilisΘ normalement)
  1917.   if (!strnotempty(fil))
  1918.     strcpy(fil,"default-index.html");
  1919.  
  1920.   // case insensitive pour adresse
  1921.   {
  1922.     char *a=jump_identification(adr);
  1923.     while(*a) {
  1924.       if ((*a>='A') && (*a<='Z'))
  1925.         *a+='a'-'A';       
  1926.       a++;
  1927.     }
  1928.   }
  1929.   
  1930.   return 0;
  1931. }
  1932.  
  1933. // simplification des ../
  1934. void fil_simplifie(char* f) {
  1935.   int i=0;
  1936.   int last=0;
  1937.   char* a;
  1938.  
  1939.   // Θliminer ../
  1940.   while (f[i]) {
  1941.     
  1942.     if (f[i]=='/') {
  1943.       if (f[i+1]=='.')
  1944.       if (f[i+2]=='.')      // couper dernier rΘpertoire
  1945.       if (f[i+3]=='/')      // Θviter les /tmp/..coolandlamedir/
  1946.       {    // couper dernier rΘpertoire
  1947.         char tempo[HTS_URLMAXSIZE*2];
  1948.         tempo[0]='\0';
  1949.         //
  1950.         if (!last)                /* can't go upper.. */
  1951.           strcpy(tempo,"/");
  1952.         else
  1953.           strncpy(tempo,f,last+1);
  1954.         tempo[last+1]='\0';
  1955.         strcat(tempo,f+i+4);
  1956.         strcpy(f,tempo);    // remplacer
  1957.         i=-1;             // recommencer
  1958.         last=0;
  1959.       }
  1960.       
  1961.       if (i>=0)
  1962.         last=i;
  1963.       else
  1964.         last=0;
  1965.     }
  1966.     
  1967.     i++;
  1968.   }
  1969.  
  1970.   // Θliminer ./
  1971.   while ( (a=strstr(f,"./")) ) {
  1972.     char tempo[HTS_URLMAXSIZE*2];
  1973.     tempo[0]='\0';
  1974.     strcpy(tempo,a+2);
  1975.     strcpy(a,tempo);
  1976.   }
  1977.   // delete all remaining ../ (potential threat)
  1978.   while ( (a=strstr(f,"../")) ) {
  1979.     char tempo[HTS_URLMAXSIZE*2];
  1980.     tempo[0]='\0';
  1981.     strcpy(tempo,a+3);
  1982.     strcpy(a,tempo);
  1983.   }
  1984.   
  1985. }
  1986.  
  1987.  
  1988. // fermer liaison fichier ou socket
  1989. HTS_INLINE void deletehttp(htsblk* r) {
  1990. #if HTS_DEBUG_CLOSESOCK
  1991.     char info[256];
  1992.     sprintf(info,"deletehttp: (htsblk*) %d\n",r);
  1993.     DEBUG_W2(info);
  1994. #endif
  1995.   if (r->soc!=INVALID_SOCKET) {
  1996.     if (r->is_file) {
  1997.       if (r->fp)
  1998.         fclose(r->fp);
  1999.       r->fp=NULL;
  2000.     } else {
  2001.       if (r->soc!=LOCAL_SOCKET_ID)
  2002.         deletesoc_r(r);
  2003.     }
  2004.     r->soc=INVALID_SOCKET;
  2005.   }
  2006. }
  2007.  
  2008. // fermer une socket
  2009. HTS_INLINE void deletesoc(T_SOC soc) {
  2010.   if (soc!=INVALID_SOCKET) {
  2011. // J'ai plantΘ.. pas de shutdown
  2012. //#if HTS_WIDE_DEBUG    
  2013. //    DEBUG_W("shutdown\n");
  2014. //#endif
  2015. //    shutdown(soc,2);  // shutdown
  2016. //#if HTS_WIDE_DEBUG    
  2017. //    DEBUG_W("shutdown done\n");
  2018. //#endif
  2019.     // Ne pas oublier de fermer la connexion avant de partir.. (plus propre)
  2020. #if HTS_WIDE_DEBUG    
  2021.     DEBUG_W("close\n");
  2022. #endif
  2023. #if HTS_WIN
  2024.     closesocket(soc);
  2025. #else
  2026.     close(soc);
  2027. #endif
  2028. #if HTS_WIDE_DEBUG    
  2029.     DEBUG_W("close done\n");
  2030. #endif
  2031.   }
  2032. }
  2033.  
  2034. /* Will also clean other things */
  2035. HTS_INLINE void deletesoc_r(htsblk* r) {
  2036. #if HTS_USEOPENSSL
  2037.   if (r->ssl_con) {
  2038.     SSL_shutdown(r->ssl_con);
  2039.     // SSL_CTX_set_quiet_shutdown(r->ssl_con->ctx, 1);
  2040.     SSL_free(r->ssl_con);
  2041.     r->ssl_con=NULL;
  2042.   }
  2043. #endif
  2044.   deletesoc(r->soc);
  2045.   r->soc=INVALID_SOCKET;
  2046. }
  2047.  
  2048. // renvoi le nombre de secondes depuis 1970
  2049. HTS_INLINE TStamp time_local(void) {
  2050.   return ((TStamp) time(NULL));
  2051. }
  2052.  
  2053. // number of millisec since 1970
  2054. HTS_INLINE TStamp mtime_local(void) {
  2055. #ifndef HTS_DO_NOT_USE_FTIME
  2056.   struct timeb B;
  2057.   ftime( &B );
  2058.   return (TStamp) ( ((TStamp) B.time * (TStamp) 1000)
  2059.         + ((TStamp) B.millitm) );
  2060. #else
  2061.   // not precise..
  2062.   return (TStamp) ( ((TStamp) time_local() * (TStamp) 1000)
  2063.         + ((TStamp) 0) );
  2064. #endif
  2065. }
  2066.  
  2067. // convertit un nombre de secondes en temps (chaine)
  2068. void sec2str(char *st,TStamp t) {
  2069.   int j,h,m,s;
  2070.   
  2071.   j=(int) (t/(3600*24));
  2072.   t-=((TStamp) j)*(3600*24);
  2073.   h=(int) (t/(3600));
  2074.   t-=((TStamp) h)*3600;
  2075.   m=(int) (t/60);
  2076.   t-=((TStamp) m)*60;
  2077.   s=(int) t;
  2078.   
  2079.   if (j>0)
  2080.     sprintf(st,"%d days, %d hours %d minutes %d seconds",j,h,m,s);
  2081.   else if (h>0)
  2082.     sprintf(st,"%d hours %d minutes %d seconds",h,m,s);
  2083.   else if (m>0)
  2084.     sprintf(st,"%d minutes %d seconds",m,s);
  2085.   else
  2086.     sprintf(st,"%d seconds",s);
  2087. }
  2088.  
  2089. // idem, plus court (chaine)
  2090. void qsec2str(char *st,TStamp t) {
  2091.   int j,h,m,s;
  2092.   
  2093.   j=(int) (t/(3600*24));
  2094.   t-=((TStamp) j)*(3600*24);
  2095.   h=(int) (t/(3600));
  2096.   t-=((TStamp) h)*3600;
  2097.   m=(int) (t/60);
  2098.   t-=((TStamp) m)*60;
  2099.   s=(int) t;
  2100.   
  2101.   if (j>0)
  2102.     sprintf(st,"%dd,%02dh,%02dmin%02ds",j,h,m,s);
  2103.   else if (h>0)
  2104.     sprintf(st,"%dh,%02dmin%02ds",h,m,s);
  2105.   else if (m>0)
  2106.     sprintf(st,"%dmin%02ds",m,s);
  2107.   else
  2108.     sprintf(st,"%ds",s);
  2109. }
  2110.  
  2111.  
  2112. // heure actuelle, GMT, format rfc (taille buffer 256o)
  2113. void time_gmt_rfc822(char* s) {
  2114.   time_t tt;
  2115.   struct tm* A;
  2116.   tt=time(NULL);
  2117.   A=gmtime(&tt);
  2118.   if (A==NULL)
  2119.     A=localtime(&tt);
  2120.   time_rfc822(s,A);
  2121. }
  2122.  
  2123. // heure actuelle, format rfc (taille buffer 256o)
  2124. void time_local_rfc822(char* s) {
  2125.   time_t tt;
  2126.   struct tm* A;
  2127.   tt=time(NULL);
  2128.   A=localtime(&tt);
  2129.   time_rfc822_local(s,A);
  2130. }
  2131.  
  2132. /* convertir une chaine en temps */
  2133. struct tm* convert_time_rfc822(char* s) {
  2134.   struct tm* result;
  2135.   /* */
  2136.   char months[]="jan feb mar apr may jun jul aug sep oct nov dec";
  2137.   char str[256];
  2138.   char* a;
  2139.   /* */
  2140.   int result_mm=-1;
  2141.   int result_dd=-1;
  2142.   int result_n1=-1;
  2143.   int result_n2=-1;
  2144.   int result_n3=-1;
  2145.   int result_n4=-1;
  2146.   /* */
  2147.   NOSTATIC_RESERVE(result, struct tm, 1);
  2148.  
  2149.   if ((int) strlen(s) > 200)
  2150.     return NULL;
  2151.   strcpy(str,s);
  2152.   hts_lowcase(str);
  2153.   /* Θliminer :,- */
  2154.   while( (a=strchr(str,'-')) ) *a=' ';
  2155.   while( (a=strchr(str,':')) ) *a=' ';
  2156.   while( (a=strchr(str,',')) ) *a=' ';
  2157.   /* tokeniser */
  2158.   a=str;
  2159.   while(*a) {
  2160.     char *first,*last;
  2161.     char tok[256];
  2162.     /* dΘcouper mot */
  2163.     while(*a==' ') a++;   /* sauter espaces */
  2164.     first=a;
  2165.     while((*a) && (*a!=' ')) a++;
  2166.     last=a;
  2167.     tok[0]='\0';
  2168.     if (first!=last) {
  2169.       char* pos;
  2170.       strncat(tok,first,(int) (last - first));
  2171.       /* analyser */
  2172.       if ( (pos=strstr(months,tok)) ) {               /* month always in letters */
  2173.         result_mm=((int) (pos - months))/4;
  2174.       } else {
  2175.         int number;
  2176.         if (sscanf(tok,"%d",&number) == 1) {      /* number token */
  2177.           if (result_dd<0)                        /* day always first number */
  2178.             result_dd=number;
  2179.           else if (result_n1<0)
  2180.             result_n1=number;
  2181.           else if (result_n2<0)
  2182.             result_n2=number;
  2183.           else if (result_n3<0)
  2184.             result_n3=number;
  2185.           else if (result_n4<0)
  2186.             result_n4=number;
  2187.         }   /* sinon, bruit de fond(+1GMT for exampel) */
  2188.       }
  2189.     }
  2190.   }
  2191.   if ((result_n1>=0) && (result_mm>=0) && (result_dd>=0) && (result_n2>=0) && (result_n3>=0) && (result_n4>=0)) {
  2192.     if (result_n4>=1000) {               /* Sun Nov  6 08:49:37 1994 */
  2193.       result->tm_year=result_n4-1900;
  2194.       result->tm_hour=result_n1;
  2195.       result->tm_min=result_n2;
  2196.       result->tm_sec=max(result_n3,0);
  2197.     } else {                            /* Sun, 06 Nov 1994 08:49:37 GMT or Sunday, 06-Nov-94 08:49:37 GMT */
  2198.       result->tm_hour=result_n2;
  2199.       result->tm_min=result_n3;
  2200.       result->tm_sec=max(result_n4,0);
  2201.       if (result_n1<=50)                /* 00 means 2000 */
  2202.         result->tm_year=result_n1+100;
  2203.       else if (result_n1<1000)          /* 99 means 1999 */
  2204.         result->tm_year=result_n1;
  2205.       else                              /* 2000 */
  2206.         result->tm_year=result_n1-1900;
  2207.     }
  2208.     result->tm_isdst=0;        /* assume GMT */
  2209.     result->tm_yday=-1;        /* don't know */
  2210.     result->tm_wday=-1;        /* don't know */
  2211.     result->tm_mon=result_mm;
  2212.     result->tm_mday=result_dd;
  2213.     return result;
  2214.   }
  2215.   return NULL;
  2216. }
  2217.  
  2218. /* sets file time. -1 if error */
  2219. int set_filetime(char* file,struct tm* tm_time) {
  2220.   struct utimbuf tim;
  2221. #ifndef HTS_DO_NOT_USE_FTIME
  2222.   struct timeb B;
  2223.   B.timezone=0;
  2224.   ftime( &B );
  2225.   tim.actime=tim.modtime=mktime(tm_time) - B.timezone*60; 
  2226. #else
  2227.   // bogus time (GMT/local)..
  2228.   tim.actime=tim.modtime=mktime(tm_time); 
  2229. #endif
  2230.   return utime(file,&tim);
  2231. }
  2232.  
  2233. /* sets file time from RFC822 date+time, -1 if error*/
  2234. int set_filetime_rfc822(char* file,char* date) {
  2235.   struct tm* tm_s=convert_time_rfc822(date);
  2236.   if (tm_s) {
  2237.     return set_filetime(file,tm_s);
  2238.   } else return -1;
  2239. }
  2240.  
  2241.  
  2242. // heure au format rfc (taille buffer 256o)
  2243. HTS_INLINE void time_rfc822(char* s,struct tm * A) {
  2244.   strftime(s,256,"%a, %d %b %Y %H:%M:%S GMT",A);
  2245. }
  2246.  
  2247. // heure locale au format rfc (taille buffer 256o)
  2248. HTS_INLINE void time_rfc822_local(char* s,struct tm * A) {
  2249.   strftime(s,256,"%a, %d %b %Y %H:%M:%S",A);
  2250. }
  2251.  
  2252. // conversion en b,Kb,Mb
  2253. char* int2bytes(LLint n) {
  2254.   char** a=int2bytes2(n);
  2255.   char* buff;
  2256.   NOSTATIC_RESERVE(buff, char, 256);
  2257.  
  2258.   strcpy(buff,a[0]);
  2259.   strcat(buff,a[1]);
  2260.   return concat(buff,"");
  2261. }
  2262.  
  2263. // conversion en b/s,Kb/s,Mb/s
  2264. char* int2bytessec(long int n) {
  2265.   char* buff;
  2266.   char** a=int2bytes2(n);
  2267.   NOSTATIC_RESERVE(buff, char, 256);
  2268.  
  2269.   strcpy(buff,a[0]);
  2270.   strcat(buff,a[1]);
  2271.   return concat(buff,"/s");
  2272. }
  2273. char* int2char(int n) {
  2274.   char* buffer;
  2275.   NOSTATIC_RESERVE(buffer, char, 32);
  2276.   sprintf(buffer,"%d",n);
  2277.   return concat(buffer,"");
  2278. }
  2279.  
  2280. // conversion en b,Kb,Mb, nombre et type sΘparΘs
  2281. // limite: 2.10^9.10^6B
  2282.  
  2283. /* See http://physics.nist.gov/cuu/Units/binary.html */
  2284. #define ToLLint(a) ((LLint)(a))
  2285. #define ToLLintKiB (ToLLint(1024))
  2286. #define ToLLintMiB (ToLLintKiB*ToLLintKiB)
  2287. #ifdef HTS_LONGLONG
  2288. #define ToLLintGiB (ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2289. #define ToLLintTiB (ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2290. #define ToLLintPiB (ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2291. #endif
  2292. typedef struct {
  2293.   char buff1[256];
  2294.   char buff2[32];
  2295.   char* buffadr[2];
  2296. } strc_int2bytes2;
  2297. char** int2bytes2(LLint n) {
  2298.   strc_int2bytes2* strc;
  2299.   NOSTATIC_RESERVE(strc, strc_int2bytes2, 1);
  2300.  
  2301.   if (n < ToLLintKiB) {
  2302.     sprintf(strc->buff1,"%d",(int)(LLint)n);
  2303.     strcpy(strc->buff2,"B");
  2304.   } else if (n < ToLLintMiB) {
  2305.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/ToLLintKiB)),(int)((LLint)((n%ToLLintKiB)*100)/ToLLintKiB));
  2306.     strcpy(strc->buff2,"KiB");
  2307.   }
  2308. #ifdef HTS_LONGLONG
  2309.   else if (n < ToLLintGiB) {
  2310.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintMiB))),(int)((LLint)(((n%(ToLLintMiB))*100)/(ToLLintMiB))));
  2311.     strcpy(strc->buff2,"MiB");
  2312.   } else if (n < ToLLintTiB) {
  2313.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintGiB))),(int)((LLint)(((n%(ToLLintGiB))*100)/(ToLLintGiB))));
  2314.     strcpy(strc->buff2,"GiB");
  2315.   } else if (n < ToLLintPiB) {
  2316.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintTiB))),(int)((LLint)(((n%(ToLLintTiB))*100)/(ToLLintTiB))));
  2317.     strcpy(strc->buff2,"TiB");
  2318.   } else {
  2319.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintPiB))),(int)((LLint)(((n%(ToLLintPiB))*100)/(ToLLintPiB))));
  2320.     strcpy(strc->buff2,"PiB");
  2321.   }
  2322. #else
  2323.   else {
  2324.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintMiB))),(int)((LLint)(((n%(ToLLintMiB))*100)/(ToLLintMiB))));
  2325.     strcpy(strc->buff2,"MiB");
  2326.   }
  2327. #endif
  2328.   strc->buffadr[0]=strc->buff1;
  2329.   strc->buffadr[1]=strc->buff2;
  2330.   return strc->buffadr;
  2331. }
  2332.  
  2333. #if HTS_WIN
  2334. #else
  2335. // ignore sigpipe?
  2336. int sig_ignore_flag( int setflag ) {     // flag ignore
  2337.   static int flag=0;   /* YES, this one is true static */
  2338.   if (setflag>=0)
  2339.     flag=setflag;
  2340.   return flag;
  2341. }
  2342. #endif
  2343.  
  2344. // envoi de texte (en tΩtes gΘnΘralement) sur la socket soc
  2345. HTS_INLINE int sendc(htsblk* r, char* s) {
  2346.   int n;
  2347.  
  2348. #if HTS_WIN
  2349. #else
  2350.   sig_ignore_flag(1);
  2351. #endif
  2352. #if HDEBUG
  2353.   write(0,s,strlen(s));
  2354. #endif
  2355.  
  2356. #if HTS_USEOPENSSL
  2357.   if (r->ssl) {
  2358.     n = SSL_write(r->ssl_con, s, strlen(s));
  2359.   } else
  2360. #endif
  2361.     n = send(r->soc,s,strlen(s),0);
  2362.  
  2363. #if HTS_WIN
  2364. #else
  2365.   sig_ignore_flag(0);
  2366. #endif
  2367.  
  2368.   return n;
  2369. }
  2370.  
  2371.  
  2372. // Remplace read
  2373. void finput(int fd,char* s,int max) {
  2374.   char c;
  2375.   int j=0;
  2376.   do {
  2377.     //c=fgetc(fp);
  2378.     if (read(fd,&c,1)<=0) {
  2379.       c=0;
  2380.     }
  2381.     if (c!=0) {
  2382.       switch(c) {
  2383.       case 10: c=0; break;
  2384.       case 13: break;  // sauter ces caractΦres
  2385.       default: s[j++]=c; break;
  2386.       }
  2387.     }
  2388.   }  while((c!=0) && (j<max-1));
  2389.   s[j++]='\0';
  2390.  
  2391. // Like linput, but in memory (optimized)
  2392. int binput(char* buff,char* s,int max) {
  2393.   char* end;
  2394.   int count;
  2395.  
  2396.   // clear buffer
  2397.   s[0]='\0';
  2398.   // end of buffer?
  2399.   if ( *buff == '\0')
  2400.     return 1;
  2401.   // find ending \n
  2402.   end=strchr(buff,'\n');
  2403.   // ..or end of buffer
  2404.   if (!end)
  2405.     end=buff+strlen(buff);
  2406.   // then count number of bytes, maximum=max
  2407.   count=min(max,end-buff);
  2408.   // and strip annoying ending cr
  2409.   while( (count>0) && (buff[count] == '\r'))
  2410.     count--;
  2411.   // copy
  2412.   if (count > 0) {
  2413.     strncat(s, buff, count);
  2414.   }
  2415.   // and terminate with a null char
  2416.   s[count]='\0';
  2417.   // then return the supplemental jump offset
  2418.   return (end-buff)+1;
  2419.  
  2420. // Lecture d'une ligne (peut Ωtre unicode α priori)
  2421. int linput(FILE* fp,char* s,int max) {
  2422.   int c;
  2423.   int j=0;
  2424.   do {
  2425.     c=fgetc(fp);
  2426.     if (c!=EOF) {
  2427.       switch(c) {
  2428.         case 13: break;  // sauter CR
  2429.         case 10: c=-1; break;
  2430.         case 9: case 12: break;  // sauter ces caractΦres
  2431.         default: s[j++]=(char) c; break;
  2432.       }
  2433.     }
  2434.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2435.   s[j]='\0';
  2436.   return j;
  2437. }
  2438. int linput_trim(FILE* fp,char* s,int max) {
  2439.   int rlen=0;
  2440.   char* ls=(char*) malloct(max+2);
  2441.   s[0]='\0';
  2442.   if (ls) {
  2443.     char* a;
  2444.     // lire ligne
  2445.     rlen=linput(fp,ls,max);
  2446.     if (rlen) {
  2447.       // sauter espaces et tabs en fin
  2448.       while( (rlen>0) && ((ls[max(rlen-1,0)]==' ') || (ls[max(rlen-1,0)]=='\t')) )
  2449.         ls[--rlen]='\0';
  2450.       // sauter espaces en dΘbut
  2451.       a=ls;
  2452.       while((rlen>0) && ((*a==' ') || (*a=='\t'))) {
  2453.         a++;
  2454.         rlen--;
  2455.       }
  2456.       if (rlen>0) {
  2457.         memcpy(s,a,rlen);      // can copy \0 chars
  2458.         s[rlen]='\0';
  2459.       }
  2460.     }
  2461.     //
  2462.     freet(ls);
  2463.   }
  2464.   return rlen;
  2465. }
  2466. int linput_cpp(FILE* fp,char* s,int max) {
  2467.   int rlen=0;
  2468.   s[0]='\0';
  2469.   do {
  2470.     int ret;
  2471.     if (rlen>0)
  2472.     if (s[rlen-1]=='\\')
  2473.       s[--rlen]='\0';      // couper \ final
  2474.     // lire ligne
  2475.     ret=linput_trim(fp,s+rlen,max-rlen);
  2476.     if (ret>0)
  2477.       rlen+=ret;
  2478.   } while((s[max(rlen-1,0)]=='\\') && (rlen<max));
  2479.   return rlen;
  2480. }
  2481.  
  2482. // idem avec les car spΘciaux
  2483. void rawlinput(FILE* fp,char* s,int max) {
  2484.   int c;
  2485.   int j=0;
  2486.   do {
  2487.     c=fgetc(fp);
  2488.     if (c!=EOF) {
  2489.       switch(c) {
  2490.         case 13: break;  // sauter CR
  2491.         case 10: c=-1; break;
  2492.         default: s[j++]=(char) c; break;
  2493.       }
  2494.     }
  2495.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2496.   s[j++]='\0';
  2497. }
  2498.  
  2499.  
  2500. // compare le dΘbut de f avec s et retourne la position de la fin
  2501. // 'A=a' (case insensitive)
  2502. int strfield(const char* f,const char* s) {
  2503.   int r=0;
  2504.   while (streql(*f,*s) && ((*f)!=0) && ((*s)!=0)) { f++; s++; r++; }
  2505.   if (*s==0)
  2506.     return r;
  2507.   else
  2508.     return 0;
  2509. }
  2510.  
  2511. //cherche chaine, case insensitive
  2512. char* strstrcase(char *s,char *o) {
  2513.   while((*s) && (strfield(s,o)==0)) s++;
  2514.   if (*s=='\0') return NULL;
  2515.   return s;  
  2516. }
  2517.  
  2518.  
  2519. // Unicode detector
  2520. // See http://www.unicode.org/unicode/reports/tr28/
  2521. // (sect Table 3.1B. Legal UTF-8 Byte Sequences)
  2522. typedef struct {
  2523.   unsigned int pos;
  2524.   unsigned char data[4];
  2525. } t_auto_seq;
  2526.  
  2527. // char between a and b
  2528. #define CHAR_BETWEEN(c, a, b)       ( (c) >= 0x##a ) && ( (c) <= 0x##b )
  2529. // sequence start
  2530. #define SEQBEG                      ( inseq == 0 )
  2531. // in this block
  2532. #define BLK(n,a, b)                 ( (seq.pos >= n) && ((err = CHAR_BETWEEN(seq.data[n], a, b))) )
  2533. #define ELT(n,a)                    BLK(n,a,a)
  2534. // end
  2535. #define SEQEND                      ((ok = 1))
  2536. // sequence started, character will fail if error
  2537. #define IN_SEQ                      ( (inseq = 1) )
  2538. // decoding error
  2539. #define BAD_SEQ                     ( (ok == 0) && (inseq != 0) && (!err) )
  2540. // no sequence started
  2541. #define NO_SEQ                      ( inseq == 0 )
  2542.  
  2543. // is this block an UTF unicode textfile?
  2544. // 0 : no
  2545. // 1 : yes
  2546. // -1: don't know
  2547. int is_unicode_utf8(unsigned char* buffer, unsigned int size) {
  2548.   t_auto_seq seq;
  2549.   unsigned int i;
  2550.   int is_utf=-1;
  2551.  
  2552.   seq.pos=0;
  2553.   for(i=0 ; i < size ; i++) {
  2554.     unsigned int ok=0;
  2555.     unsigned int inseq=0;
  2556.     unsigned int err=0;
  2557.  
  2558.     seq.data[seq.pos]=buffer[i];
  2559.     /**/ if ( SEQBEG && BLK(0,00,7F) && IN_SEQ && SEQEND                                                 ) { }
  2560.     else if ( SEQBEG && BLK(0,C2,DF) && IN_SEQ && BLK(1,80,BF) && SEQEND                                 ) { }
  2561.     else if ( SEQBEG && ELT(0,E0   ) && IN_SEQ && BLK(1,A0,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  2562.     else if ( SEQBEG && BLK(0,E1,EC) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  2563.     else if ( SEQBEG && ELT(0,ED   ) && IN_SEQ && BLK(1,80,9F) && BLK(2,80,BF) && SEQEND                 ) { }
  2564.     else if ( SEQBEG && BLK(0,EE,EF) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  2565.     else if ( SEQBEG && ELT(0,F0   ) && IN_SEQ && BLK(1,90,BF) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  2566.     else if ( SEQBEG && BLK(0,F1,F3) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  2567.     else if ( SEQBEG && ELT(0,F4   ) && IN_SEQ && BLK(1,80,8F) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  2568.     else if ( NO_SEQ ) {    // bad, unknown
  2569.       return 0;
  2570.     }
  2571.     /* */
  2572.     
  2573.     /* Error */
  2574.     if ( BAD_SEQ ) {
  2575.       return 0;
  2576.     }
  2577.  
  2578.     /* unicode character */
  2579.     if (seq.pos > 0)
  2580.       is_utf=1;
  2581.  
  2582.     /* Next */
  2583.     if (ok)
  2584.       seq.pos=0;
  2585.     else
  2586.       seq.pos++;
  2587.  
  2588.     /* Internal error */
  2589.     if (seq.pos >= 4)
  2590.       return 0;
  2591.  
  2592.   }
  2593.  
  2594.   return is_utf;
  2595. }
  2596.  
  2597.  
  2598. // le fichier est-il un fichier html?
  2599. //  0 : non
  2600. //  1 : oui
  2601. // -1 : on sait pas
  2602. // -2 : on sait pas, pas d'extension
  2603. int ishtml(char* fil) {
  2604.   char *a;
  2605.  
  2606.   // patch pour les truc.html?Choix=toto
  2607.   if ( (a=strchr(fil,'?')) )  // paramΦtres?
  2608.     a--;  // pointer juste avant le ?
  2609.   else
  2610.     a=fil+strlen(fil)-1;  // pointer sur le dernier caractΦre
  2611.  
  2612.   if (*a=='/') return -1;    // rΘpertoire, on sait pas!!
  2613.   //if (*a=='/') return 1;    // ok rΘpertoire, html
  2614.  
  2615.   while ( (*a!='.') && (*a!='/')  && ( a > fil)) a--;
  2616.   if (*a=='.') {  // a une extension
  2617.     char fil_noquery[HTS_URLMAXSIZE*2];
  2618.     fil_noquery[0]='\0';
  2619.     a++;  // pointer sur extension
  2620.     strncat(fil_noquery,a,HTS_URLMAXSIZE);
  2621.     a=strchr(fil_noquery,'?');
  2622.     if (a)
  2623.       *a='\0';
  2624.     return ishtml_ext(fil_noquery);     // retour
  2625.   } else return -2;   // indΘterminΘ, par exemple /truc
  2626. }
  2627.  
  2628. // idem, mais pour uniquement l'extension
  2629. int ishtml_ext(char* a) {
  2630.   int html=0;  
  2631.   //
  2632.   if (strfield2(a,"html"))       html = 1;
  2633.   else if (strfield2(a,"htm"))   html = 1;
  2634.   else if (strfield2(a,"shtml")) html = 1;
  2635.   else if (strfield2(a,"phtml")) html = 1;
  2636.   else if (strfield2(a,"htmlx")) html = 1;
  2637.   else if (strfield2(a,"shtm"))  html = 1;
  2638.   else if (strfield2(a,"phtm"))  html = 1;
  2639.   else if (strfield2(a,"htmx"))  html = 1;
  2640.   //
  2641.   // insuccΦs..
  2642.   else {
  2643.     switch(is_knowntype(a)) {
  2644.     case 1:
  2645.       html = 0;     // connu, non html
  2646.       break;
  2647.     case 2:
  2648.       html = 1;     // connu, html
  2649.       break;
  2650.     default:
  2651.       html = -1;    // inconnu..
  2652.       break;
  2653.     }
  2654.   }
  2655.   return html;  
  2656. }
  2657.  
  2658. // error (404,500..)
  2659. HTS_INLINE int ishttperror(int err) {
  2660.   switch (err/100) {
  2661.     case 4: case 5: return 1;
  2662.       break;
  2663.   }
  2664.   return 0;
  2665. }
  2666.  
  2667.  
  2668. // retourne le pointeur ou le pointeur + offset si il existe dans la chaine un @ signifiant 
  2669. // une identification
  2670. char* jump_identification(char* source) {
  2671.   char *a,*trytofind;
  2672.   // rechercher dernier @ (car parfois email transmise dans adresse!)
  2673.   // mais sauter ftp:// Θventuel
  2674.   a = jump_protocol(source);
  2675.   trytofind = strrchr_limit(a, '@', strchr(a,'/'));
  2676.   return (trytofind != NULL)?trytofind:a;
  2677. }
  2678.  
  2679. // find port (:80) or NULL if not found
  2680. // can handle IPV6 addresses
  2681. char* jump_toport(char* source) {
  2682.   char *a,*trytofind;
  2683.   a = jump_identification(source);
  2684.   trytofind = strrchr_limit(a, ']', strchr(source, '/'));    // find last ] (http://[3ffe:b80:1234::1]:80/foo.html)
  2685.   a = strchr( (trytofind)?trytofind:a, ':');
  2686.   return a;
  2687. }
  2688.  
  2689. // strrchr, but not too far
  2690. char* strrchr_limit(char* s, char c, char* limit) {
  2691.   if (limit == NULL) {
  2692.     char* p = strchr(s, c);
  2693.     return p?(p+1):NULL;
  2694.   } else {
  2695.     char *a=NULL, *p;
  2696.     for(;;) {
  2697.       p=strchr((a)?a:s, c);
  2698.       if ((p >= limit) || (p == NULL))
  2699.         return a;
  2700.       a=p+1;
  2701.     }
  2702.   }
  2703. }
  2704.  
  2705. // retourner adr sans ftp://
  2706. HTS_INLINE char* jump_protocol(char* source) {
  2707.   int p;
  2708.   // scheme
  2709.   // "Comparisons of scheme names MUST be case-insensitive" (RFC2616)
  2710.   if ((p=strfield(source,"http:")))
  2711.     source+=p;
  2712.   else if ((p=strfield(source,"ftp:")))
  2713.     source+=p;
  2714. #if HTS_USEOPENSSL
  2715.   else if ((p=strfield(source,"https:")))
  2716.     source+=p;
  2717. #endif
  2718.   // net_path
  2719.   if (strncmp(source,"//",2)==0)
  2720.     source+=2;
  2721.   return source;
  2722. }
  2723.  
  2724. // codage base 64 a vers b
  2725. void code64(char* a,char* b) {
  2726.   int i1=0,i2=0,i3=0,i4=0;
  2727.   unsigned long store;
  2728.   int n;
  2729.   const char _hts_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  2730.   b[0]='\0';
  2731.   while(*a) {  
  2732.     // 24 bits
  2733.     n=1; store=0; store |= ((*a++) & 0xff);
  2734.     if (*a) { n=2; store <<= 8; store |= ((*a++) & 0xff); }
  2735.     if (*a) { n=3; store <<= 8; store |= ((*a++) & 0xff); }
  2736.     if (n==3) {
  2737.       i4=store & 63;
  2738.       i3=(store>>6) & 63;
  2739.       i2=(store>>12) & 63;
  2740.       i1=(store>>18) & 63;
  2741.     } else if (n==2) {
  2742.       store<<=2;    
  2743.       i3=store & 63;
  2744.       i2=(store>>6) & 63;
  2745.       i1=(store>>12) & 63;
  2746.     } else {
  2747.       store<<=4;
  2748.       i2=store & 63;
  2749.       i1=(store>>6) & 63;
  2750.     }
  2751.     
  2752.     *b++ = _hts_base64[i1];
  2753.     *b++ = _hts_base64[i2];
  2754.     if (n>=2)
  2755.       *b++ = _hts_base64[i3];
  2756.     else
  2757.       *b++ = '=';
  2758.     if (n>=3)
  2759.       *b++ = _hts_base64[i4];
  2760.     else
  2761.       *b++ = '=';
  2762.   }
  2763.   *b++='\0';
  2764. }
  2765.  
  2766. // remplacer " par " etc..
  2767. // buffer MAX 1Ko
  2768. void unescape_amp(char* s) {
  2769.   while(*s) {
  2770.     if (*s=='&') {
  2771.       char* end=strchr(s,';');
  2772.       if ( ((int) (end - s)) <= 8) {
  2773.         char c=0;
  2774.         if (strfield(s,"&"))
  2775.           c='&';
  2776.         else if (strfield(s,"°"))
  2777.           c='░';
  2778.         else if (strfield(s,">"))
  2779.           c='>';
  2780.         else if (strfield(s,"«"))
  2781.           c='\"';
  2782.         else if (strfield(s,"<"))
  2783.           c='<';
  2784.         else if (strfield(s," "))
  2785.           c=' ';
  2786.         else if (strfield(s,"""))
  2787.           c='\"';
  2788.         else if (strfield(s,"»"))
  2789.           c='\"';
  2790.         else if (strfield(s,"­"))
  2791.           c='-';
  2792.         else if (strfield(s,"˜"))
  2793.           c='~';
  2794.         else if (strfield(s,"&"))
  2795.           c='&';
  2796.         // remplacer?
  2797.         if (c) {
  2798.           char buff[HTS_URLMAXSIZE*2];
  2799.           buff[0]=c;
  2800.           strcpy(buff+1,end+1);
  2801.           strcpy(s,buff);
  2802.         }
  2803.       }
  2804.     }
  2805.     s++;
  2806.   }
  2807. }
  2808.  
  2809. // remplacer %20 par ' ', | par : etc..
  2810. // buffer MAX 1Ko
  2811. char* unescape_http(char* s) {
  2812.   char* tempo;
  2813.   int i,j=0;
  2814.   NOSTATIC_RESERVE(tempo, char, HTS_URLMAXSIZE*2);
  2815.   for (i=0;i<(int) strlen(s);i++) {
  2816.     if (s[i]=='%') {
  2817.       i++;
  2818.       tempo[j++]=(char) ehex(s+i);
  2819.       i++;    // sauter 2 caractΦres finalement
  2820.     }
  2821.     /*
  2822.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  2823.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  2824.       tempo[j++]=':';
  2825.     }
  2826.     */
  2827.     else
  2828.       tempo[j++]=s[i];
  2829.   }
  2830.   tempo[j++]='\0';
  2831.   return tempo;
  2832. }
  2833.  
  2834. // unescape in URL/URI ONLY what has to be escaped, to form a standard URL/URI
  2835. char* unescape_http_unharm(char* s, int no_high) {
  2836.   char* tempo;
  2837.   int i,j=0;
  2838.   NOSTATIC_RESERVE(tempo, char, HTS_URLMAXSIZE*2);
  2839.   for (i=0;i<(int) strlen(s);i++) {
  2840.     if (s[i]=='%') {
  2841.       int nchar=(char) ehex(s+i+1);
  2842.  
  2843.       int test = (  CHAR_RESERVED(nchar)
  2844.                 || CHAR_DELIM(nchar)
  2845.                 || CHAR_UNWISE(nchar)
  2846.                 || CHAR_LOW(nchar)        /* CHAR_SPECIAL */
  2847.                 || CHAR_XXAVOID(nchar) 
  2848.                 || (
  2849.                   (no_high)
  2850.                   &&
  2851.                   CHAR_HIG(nchar)
  2852.                 )
  2853.                 );
  2854.  
  2855.       if (!test) {
  2856.         tempo[j++]=(char) ehex(s+i+1);
  2857.         i+=2;
  2858.       } else {
  2859.         tempo[j++]='%';
  2860.       }
  2861.     }
  2862.     /*
  2863.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  2864.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  2865.       tempo[j++]=':';
  2866.     }
  2867.     */
  2868.     else
  2869.       tempo[j++]=s[i];
  2870.   }
  2871.   tempo[j++]='\0';
  2872.   return tempo;
  2873. }
  2874.  
  2875. // remplacer " par %xx etc..
  2876. // buffer MAX 1Ko
  2877. void escape_spc_url(char* s) {
  2878.   x_escape_http(s,2);
  2879. }
  2880. // smith / john -> smith%20%2f%20john
  2881. void escape_in_url(char* s) {
  2882.   x_escape_http(s,1);
  2883. }
  2884. // smith / john -> smith%20/%20john
  2885. void escape_uri(char* s) {
  2886.   x_escape_http(s,3);
  2887. }
  2888. void escape_uri_utf(char* s) {
  2889.   x_escape_http(s,30);
  2890. }
  2891. void escape_check_url(char* s) {
  2892.   x_escape_http(s,0);
  2893. }
  2894. // same as escape_check_url, but returns char*
  2895. char* escape_check_url_addr(char* s) {
  2896.   char* adr;
  2897.   escape_check_url(adr = concat(s,""));
  2898.   return adr;
  2899. }
  2900.  
  2901.  
  2902. void x_escape_http(char* s,int mode) {
  2903.   while(*s) {
  2904.     int test=0;
  2905.     if (mode == 0)
  2906.       test=(strchr("\" ",*s)!=0);
  2907.     else if (mode==1) {
  2908.       test = (  CHAR_RESERVED(*s)
  2909.              || CHAR_DELIM(*s)
  2910.              || CHAR_UNWISE(*s)
  2911.              || CHAR_SPECIAL(*s)
  2912.              || CHAR_XXAVOID(*s) );
  2913.     }
  2914.     else if (mode==2)
  2915.       test=(strchr(" ",*s)!=0);           // n'escaper que espace
  2916.     else if (mode==3) {                   // Θchapper que ce qui est nΘcessaire
  2917.       test = (
  2918.                 CHAR_SPECIAL(*s)
  2919.              || CHAR_XXAVOID(*s) );
  2920.     }
  2921.     else if (mode==30) {                   // Θchapper que ce qui est nΘcessaire
  2922.       test = (
  2923.                 CHAR_LOW(*s)
  2924.              || CHAR_XXAVOID(*s) );
  2925.     }
  2926.  
  2927.     if (test) {
  2928.       char buffer[HTS_URLMAXSIZE*2];
  2929.       int n;
  2930.       n=(int)(unsigned char) *s;
  2931.       strcpy(buffer,s+1);
  2932.       sprintf(s,"%%%02x",n);
  2933.       strcat(s,buffer);
  2934.     }
  2935.     s++;
  2936.   }
  2937. }
  2938.  
  2939.  
  2940. HTS_INLINE int ehexh(char c) {
  2941.   if ((c>='0') && (c<='9')) return c-'0';
  2942.   if ((c>='a') && (c<='f')) c-=('a'-'A');
  2943.   if ((c>='A') && (c<='F')) return (c-'A'+10);
  2944.   return 0;
  2945. }
  2946.  
  2947. HTS_INLINE int ehex(char* s) {
  2948.   return 16*ehexh(*s)+ehexh(*(s+1));
  2949.  
  2950. }
  2951.  
  2952. // concat, concatΦne deux chaines et renvoi le rΘsultat
  2953. // permet d'allΘger grandement le code
  2954. // il faut savoir qu'on ne peut mettre plus de 16 concat() dans une expression
  2955. typedef struct {
  2956.   char buff[16][HTS_URLMAXSIZE*2*2];
  2957.   int rol;
  2958. } concat_strc;
  2959. char* concat(const char* a,const char* b) {
  2960.   concat_strc* strc;
  2961.   NOSTATIC_RESERVE(strc, concat_strc, 1);
  2962.   strc->rol=((strc->rol+1)%16);    // roving pointer
  2963.   strcpy(strc->buff[strc->rol],a);
  2964.   if (b) strcat(strc->buff[strc->rol],b);
  2965.   return strc->buff[strc->rol];
  2966. }
  2967. // conversion fichier / -> antislash
  2968. #if HTS_DOSNAME
  2969. char* __fconv(char* a) {
  2970.   int i;
  2971.   for(i=0;i<(int) strlen(a);i++)
  2972.     if (a[i]=='/')  // convertir
  2973.       a[i]='\\';
  2974.   return a;
  2975. }
  2976. char* fconcat(char* a,char* b) {
  2977.   return __fconv(concat(a,b));
  2978. }
  2979. char* fconv(char* a) {
  2980.   return __fconv(concat(a,""));
  2981. }
  2982. #endif
  2983.  
  2984. /* / et \\ en / */
  2985. char* __fslash(char* a) {
  2986.   int i;
  2987.   for(i=0;i<(int) strlen(a);i++)
  2988.     if (a[i]=='\\')  // convertir
  2989.       a[i]='/';
  2990.   return a;
  2991. }
  2992. char* fslash(char* a) {
  2993.   return __fslash(concat(a,""));
  2994. }
  2995.  
  2996. // conversion minuscules, avec buffer
  2997. char* convtolower(char* a) {
  2998.   concat_strc* strc;
  2999.   NOSTATIC_RESERVE(strc, concat_strc, 1);
  3000.   strc->rol=((strc->rol+1)%16);    // roving pointer
  3001.   strcpy(strc->buff[strc->rol],a);
  3002.   hts_lowcase(strc->buff[strc->rol]);  // lower case
  3003.   return strc->buff[strc->rol];
  3004. }
  3005.  
  3006. // conversion en minuscules
  3007. void hts_lowcase(char* s) {
  3008.   int i;
  3009.   for(i=0;i<(int) strlen(s);i++)
  3010.     if ((s[i]>='A') && (s[i]<='Z'))
  3011.       s[i]+=('a'-'A');
  3012. }
  3013.  
  3014. // remplacer un caractΦre d'une chaεne dans une autre
  3015. HTS_INLINE void hts_replace(char *s,char from,char to) { 
  3016.   char* a;
  3017.   while ((a=strchr(s,from))!=NULL) {
  3018.     *a=to;
  3019.   }
  3020. }
  3021.  
  3022.  
  3023. // caractΦre espace, guillemets, CR, LF etc..
  3024. /* SECTION OPTIMISEE:
  3025.   #define  is_space(c) (strchr(" \"\x0d\x0a\x09'",c)!=NULL)
  3026.   #define  is_realspace(c) (strchr(" \x0d\x0a\x09",c)!=NULL)
  3027. */
  3028. /*
  3029. HTS_INLINE int is_space(char c) {
  3030.   if (c==' ')  return 1;  // spc
  3031.   if (c=='"')  return 1;  // quote
  3032.   if (c==10)   return 1;  // lf
  3033.   if (c==13)   return 1;  // cr
  3034.   if (c=='\'') return 1;  // quote
  3035.   //if (c=='`')  return 1;  // backquote      << non
  3036.   if (c==9)    return 1;  // tab
  3037.   return 0;
  3038. }
  3039. */
  3040.  
  3041. // caractΦre espace, CR, LF, TAB
  3042. /*
  3043. HTS_INLINE int is_realspace(char c) {
  3044.   if (c==' ')  return 1;  // spc
  3045.   if (c==10)   return 1;  // lf
  3046.   if (c==13)   return 1;  // cr
  3047.   if (c==9)    return 1;  // tab
  3048.   return 0;
  3049. }
  3050. */
  3051.  
  3052.  
  3053.  
  3054.  
  3055.  
  3056. // deviner type d'un fichier local..
  3057. // ex: fil="toto.gif" -> s="image/gif"
  3058. void guess_httptype(char *s,char *fil) {
  3059.   get_httptype(s,fil,1);
  3060. }
  3061. // idem
  3062. // flag: 1 si toujours renvoyer un type
  3063. void get_httptype(char *s,char *fil,int flag) {
  3064.   if (ishtml(fil)==1)
  3065.     strcpy(s,"text/html");
  3066.   else {
  3067.     char *a=fil+strlen(fil)-1;    
  3068.     while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  3069.     if (*a=='.') {
  3070.       int ok=0;
  3071.       int j=0;
  3072.       a++;
  3073.       while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  3074.         if (strfield2(hts_mime[j][1],a)) {
  3075.           if (hts_mime[j][0][0]!='*') {    // Une correspondance existe
  3076.             strcpy(s,hts_mime[j][0]);
  3077.             ok=1;
  3078.           }
  3079.         }
  3080.         j++;
  3081.       }
  3082.       
  3083.       if (!ok) if (flag) sprintf(s,"application/%s",a);
  3084.     } else {
  3085.       if (flag) strcpy(s,"application/octet-stream");
  3086.     }
  3087.   }
  3088. }
  3089.  
  3090. // get type of fil (php)
  3091. // s: buffer (text/html) or NULL
  3092. // return: 1 if known by user
  3093. int get_userhttptype(int setdefs,char *s,char *ext) {
  3094.   char** buffer=NULL;
  3095.   NOSTATIC_RESERVE(buffer, char*, 1);
  3096.   if (setdefs) {
  3097.     *buffer=s;
  3098.     return 1;
  3099.   } else {
  3100.     if (s)
  3101.       s[0]='\0';
  3102.     if (!ext)
  3103.       return 0;
  3104.     if (*buffer) {
  3105.       char search[1024];
  3106.       char* detect;
  3107.       sprintf(search,"\n%s=",ext);    // php=text/html
  3108.       detect=strstr(*buffer,search);
  3109.       if (!detect) {
  3110.         sprintf(search,"\n%s\n",ext); // php\ncgi=text/html
  3111.         detect=strstr(*buffer,search);
  3112.       }
  3113.       if (detect) {
  3114.         detect=strchr(detect,'=');
  3115.         if (detect) {
  3116.           detect++;
  3117.           if (s) {
  3118.             char* a;
  3119.             a=strchr(detect,'\n');
  3120.             if (a) {
  3121.               strncat(s,detect,(int) (a - detect));
  3122.             }
  3123.           }
  3124.           return 1;
  3125.         }
  3126.       }
  3127.     }
  3128.   }
  3129.   return 0;
  3130. }
  3131. // renvoyer extesion d'un type mime..
  3132. // ex: "image/gif" -> gif
  3133. void give_mimext(char *s,char *st) {   
  3134.   int ok=0;
  3135.   int j=0;
  3136.   s[0]='\0';
  3137.   while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  3138.     if (strfield2(hts_mime[j][0],st)) {
  3139.       if (hts_mime[j][1][0]!='*') {    // Une correspondance existe
  3140.         strcpy(s,hts_mime[j][1]);
  3141.         ok=1;
  3142.       }
  3143.     }
  3144.     j++;
  3145.   }
  3146.   // wrap "x" mimetypes, such as:
  3147.   // application/x-mp3
  3148.   // or
  3149.   // application/mp3
  3150.   if (!ok) {
  3151.     int p;
  3152.     char* a=NULL;
  3153.     if ((p=strfield(st,"application/x-")))
  3154.       a=st+p;
  3155.     else if ((p=strfield(st,"application/")))
  3156.       a=st+p;
  3157.     if (a) {
  3158.       if ((int)strlen(a) >= 1) {
  3159.         if ((int)strlen(a) <= 4) {
  3160.           strcpy(s,a);
  3161.           ok=1;
  3162.         }
  3163.       }
  3164.     }
  3165.   }
  3166. }
  3167. // extension connue?..
  3168. //  0 : non
  3169. //  1 : oui
  3170. //  2 : html
  3171. int is_knowntype(char *fil) {
  3172.   int j=0;
  3173.   if (!fil)
  3174.     return 0;
  3175.   while(strnotempty(hts_mime[j][1])) {
  3176.     if (strfield2(hts_mime[j][1],fil)) {
  3177.       if (strfield2(hts_mime[j][0],"text/html"))
  3178.         return 2;
  3179.       else
  3180.         return 1;
  3181.     }
  3182.     j++;
  3183.   }
  3184.  
  3185.   // Known by user?
  3186.   return (is_userknowntype(fil));
  3187. }
  3188. // extension : html,gif..
  3189. char* get_ext(char *fil) {
  3190.   char* fil_noquery;
  3191.   char *a=fil+strlen(fil)-1;    
  3192.   NOSTATIC_RESERVE(fil_noquery, char, HTS_URLMAXSIZE*2);
  3193.  
  3194.   while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  3195.   if (*a=='.') {
  3196.     fil_noquery[0]='\0';
  3197.     a++;  // pointer sur extension
  3198.     strncat(fil_noquery,a,HTS_URLMAXSIZE);
  3199.     a=strchr(fil_noquery,'?');
  3200.     if (a)
  3201.       *a='\0';
  3202.     return concat(fil_noquery,"");
  3203.   }
  3204.   else
  3205.     return "";
  3206. }
  3207. // known type?..
  3208. //  0 : no
  3209. //  1 : yes
  3210. //  2 : html
  3211. // setdefs : set mime buffer:
  3212. //   file=(char*) "asp=text/html\nphp=text/html\n"
  3213. int is_userknowntype(char *fil) {
  3214.   char mime[1024];
  3215.   if (!fil)
  3216.     return 0;
  3217.   if (!strnotempty(fil))
  3218.     return 0;
  3219.   mime[0]='\0';
  3220.   get_userhttptype(0,mime,fil);
  3221.   if (!strnotempty(mime))
  3222.     return 0;
  3223.   else if (strfield2(mime,"text/html"))
  3224.     return 2;
  3225.   else
  3226.     return 1;
  3227. }
  3228.  
  3229. // page dynamique?
  3230. // is_dyntype(get_ext("foo.asp"))
  3231. int is_dyntype(char *fil) {
  3232.   int j=0;
  3233.   if (!fil)
  3234.     return 0;
  3235.   if (!strnotempty(fil))
  3236.     return 0;
  3237.   while(strnotempty(hts_ext_dynamic[j])) {
  3238.     if (strfield2(hts_ext_dynamic[j],fil)) {
  3239.       return 1;
  3240.     }
  3241.     j++;
  3242.   }
  3243.   return 0;
  3244. }
  3245.  
  3246. // types critiques qui ne doivent pas Ωtre changΘs car renvoyΘs par des serveurs qui ne
  3247. // connaissent pas le type
  3248. int may_unknown(char* st) {
  3249.   int j=0;
  3250.   // types mΘdia
  3251.   if (may_be_hypertext_mime(st))
  3252.     return 1;
  3253.   while(strnotempty(hts_mime_keep[j])) {
  3254.     if (strfield2(hts_mime_keep[j],st)) {      // trouvΘ
  3255.       return 1;
  3256.     }
  3257.     j++;
  3258.   }    
  3259.   return 0;
  3260. }
  3261.  
  3262.  
  3263.  
  3264. // -- Utils fichiers
  3265.  
  3266. // pretty print for i/o
  3267. void fprintfio(FILE* fp,char* buff,char* prefix) {
  3268.   char nl=1;
  3269.   while(*buff) {
  3270.     switch(*buff) {
  3271.     case 13: break;
  3272.     case 10:
  3273.       fprintf(fp,"\r\n");
  3274.       nl=1;
  3275.     break;
  3276.     default:
  3277.       if (nl)
  3278.         fprintf(fp,prefix);
  3279.       nl=0;
  3280.       fputc(*buff,fp);
  3281.     }
  3282.     buff++;
  3283.   }
  3284. }
  3285.  
  3286. /* Le fichier existe-t-il? (ou est-il accessible?) */
  3287. int fexist(char* s) {
  3288.   FILE* fp;
  3289.   if (strnotempty(s)==0)     // nom vide: non trouvΘ
  3290.     return 0;
  3291.   fp=fopen(fconv(s),"rb");
  3292.   if (fp!=NULL) fclose(fp);
  3293.   return (fp!=NULL);
  3294.  
  3295. /* Taille d'un fichier, -1 si n'existe pas */
  3296. /* fp->_cnt ne fonctionne pas sur toute les plate-formes :-(( */
  3297. /* Note: NOT YET READY FOR 64-bit */
  3298. //LLint fsize(char* s) {
  3299. int fsize(char* s) {
  3300.   /*
  3301. #if HTS_WIN
  3302.   HANDLE hFile;
  3303.   DWORD dwSizeHigh = 0;
  3304.   DWORD dwSizeLow  = 0;
  3305.   hFile = CreateFile(s,0,0,NULL,OPEN_EXISTING,0,NULL);
  3306.   if (hFile) {
  3307.     dwSizeLow = GetFileSize (hFile, & dwSizeHigh) ;
  3308.     CloseHandle(hFile);
  3309.     if (dwSizeLow != 0xFFFFFFFF)
  3310.       return (dwSizeLow & (dwSizeHigh<<32));
  3311.     else
  3312.       return -1;
  3313.   } else
  3314.     return -1;
  3315. #else
  3316.     */
  3317.   FILE* fp;
  3318.   if (strnotempty(s)==0)     // nom vide: erreur
  3319.     return -1;
  3320.   fp=fopen(fconv(s),"rb");
  3321.   if (fp!=NULL) {
  3322.     int i;
  3323.     fseek(fp,0,SEEK_END);
  3324.     i=ftell(fp);
  3325.     fclose(fp);
  3326.     return i;
  3327.   } else return -1;
  3328.   /*
  3329. #endif
  3330.   */
  3331. }
  3332.  
  3333. int fpsize(FILE* fp) {
  3334.   int oldpos,size;
  3335.   if (!fp)
  3336.     return -1;
  3337.   oldpos=ftell(fp);
  3338.   fseek(fp,0,SEEK_END);
  3339.   size=ftell(fp);
  3340.   fseek(fp,oldpos,SEEK_SET);
  3341.   return size;
  3342. }
  3343.  
  3344. /* root dir, with ending / */
  3345. typedef struct {
  3346.   char path[1024+4];
  3347.   int init;
  3348. } hts_rootdir_strc;
  3349. char* hts_rootdir(char* file) {
  3350.   hts_rootdir_strc* strc;
  3351.   NOSTATIC_RESERVE(strc, hts_rootdir_strc, 1);
  3352.   if (file) {
  3353.     if (!strc->init) {
  3354.       strc->path[0]='\0';
  3355.       strc->init=1;
  3356.       if (strnotempty(file)) {
  3357.         char* a;
  3358.         strcpy(strc->path,file);
  3359.         while((a=strrchr(strc->path,'\\'))) *a='/';
  3360.         if ((a=strrchr(strc->path,'/'))) {
  3361.           *(a+1)='\0';
  3362.         } else
  3363.           strc->path[0]='\0';
  3364.       }
  3365.       if (!strnotempty(strc->path)) {
  3366.         if( getcwd( strc->path, 1024 ) == NULL )
  3367.             strc->path[0]='\0';
  3368.         else
  3369.           strcat(strc->path,"/");
  3370.       }
  3371.     }
  3372.     return NULL;
  3373.   } else if (strc->init)
  3374.     return strc->path;
  3375.   else
  3376.     return "";
  3377. }
  3378.  
  3379.  
  3380.  
  3381. hts_stat_struct HTS_STAT;
  3382. //
  3383. // return  number of downloadable bytes, depending on rate limiter
  3384. // see engine_stats() routine, too
  3385. // this routine works quite well for big files and regular ones, but apparently the rate limiter has
  3386. // some problems with very small files (rate too high)
  3387. LLint check_downloadable_bytes(int rate) {
  3388.   if (rate>0) {
  3389.     TStamp time_now;
  3390.     TStamp elapsed_useconds;
  3391.     LLint bytes_transfered_during_period;
  3392.     LLint left;
  3393.  
  3394.     // get the older timer
  3395.     int id_timer = (HTS_STAT.istat_idlasttimer + 1) % 2;
  3396.  
  3397.     time_now=mtime_local();
  3398.     elapsed_useconds = time_now - HTS_STAT.istat_timestart[id_timer];
  3399.     // NO totally stupid - elapsed_useconds+=1000;      // for the next second, too
  3400.     bytes_transfered_during_period = (HTS_STAT.HTS_TOTAL_RECV-HTS_STAT.istat_bytes[id_timer]);
  3401.     
  3402.     left = ((rate * elapsed_useconds)/1000) - bytes_transfered_during_period;
  3403.     if (left <= 0)
  3404.       left = 0;
  3405.     
  3406.     return left;
  3407.   } else
  3408.     return TAILLE_BUFFER;
  3409. }
  3410.  
  3411. //
  3412. // 0 : OK
  3413. // 1 : slow down
  3414. #if 0
  3415. int HTS_TOTAL_RECV_CHECK(int var) {
  3416.   if (HTS_STAT.HTS_TOTAL_RECV_STATE)
  3417.     return 1;
  3418.     /*
  3419.     {
  3420.     if (HTS_STAT.HTS_TOTAL_RECV_STATE==3) { 
  3421.       var = min(var,32); 
  3422.       Sleep(250); 
  3423.     } else if (HTS_STAT.HTS_TOTAL_RECV_STATE==2) { 
  3424.       var = min(var,256); 
  3425.       Sleep(100); 
  3426.     } else { 
  3427.       var/=2; 
  3428.       if (var<=0) var=1; 
  3429.       Sleep(50); 
  3430.     } 
  3431.   }
  3432.     */
  3433.   return 0;
  3434. }
  3435. #endif
  3436.  
  3437. // Lecture dans buff de size octets au maximum en utilisant la socket r (structure htsblk)
  3438. // >0 : data received
  3439. // == 0 : not yet data
  3440. // <0 : no more data or error
  3441. HTS_INLINE int hts_read(htsblk* r,char* buff,int size) {
  3442.   int retour;
  3443.   //  return read(soc,buff,size);
  3444.   if (r->is_file) {
  3445. #if HTS_WIDE_DEBUG    
  3446.     DEBUG_W("read\n");
  3447. #endif
  3448.     if (r->fp)
  3449.       retour=fread(buff,1,size,r->fp);
  3450.     else
  3451.       retour=-1;
  3452.   } else {
  3453. #if HTS_WIDE_DEBUG    
  3454.     DEBUG_W("recv\n");
  3455.     if (r->soc==INVALID_SOCKET)
  3456.       printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
  3457. #endif
  3458.     //HTS_TOTAL_RECV_CHECK(size);         // Diminuer au besoin si trop de donnΘes reτues
  3459. #if HTS_USEOPENSSL
  3460.     if (r->ssl) {
  3461.       retour = SSL_read(r->ssl_con, buff, size);
  3462.       if (retour <= 0) {
  3463.         int err_code = SSL_get_error(r->ssl_con, retour);
  3464.         if (
  3465.           (err_code == SSL_ERROR_WANT_READ)
  3466.           ||
  3467.           (err_code == SSL_ERROR_WANT_WRITE)
  3468.           ) 
  3469.         {
  3470.           retour = 0;             /* no data yet (ssl cache) */
  3471.         } else {
  3472.           retour = -1;            /* eof or error */
  3473.         }
  3474.       }
  3475.     } else {
  3476. #endif
  3477.     retour=recv(r->soc,buff,size,0);
  3478.   }
  3479.   if (retour > 0)    // compter flux entrant
  3480.     HTS_STAT.HTS_TOTAL_RECV+=retour;
  3481. #if HTS_USEOPENSSL
  3482.   }
  3483. #endif
  3484. #if HTS_WIDE_DEBUG    
  3485.   DEBUG_W("recv/read done\n");
  3486. #endif
  3487.   return retour;
  3488. }
  3489.  
  3490.  
  3491. // -- Gestion cache DNS --
  3492. // 'RX98
  3493. #if HTS_DNSCACHE
  3494.  
  3495. // 'capsule' contenant uniquement le cache
  3496. t_dnscache* _hts_cache(void) {
  3497.   t_dnscache* cache;
  3498.   NOSTATIC_RESERVE(cache, t_dnscache, 1);
  3499.   return cache;
  3500. }
  3501.  
  3502. // lock le cache dns pour tout opΘration d'ajout
  3503. // plus prudent quand plusieurs threads peuvent Θcrire dedans..
  3504. // -1: status? 0: libΘrer 1:locker
  3505.  
  3506. /* 
  3507.   Simple lock function for cache
  3508.  
  3509.   Return value: always 0
  3510.   Parameter:
  3511.   1 wait for lock (mutex) available and lock it
  3512.   0 unlock the mutex
  3513.   [-1 check if locked (always return 0 with mutex)]
  3514.   -999 initialize
  3515. */
  3516. #if USE_BEGINTHREAD
  3517. int _hts_lockdns(int i) {
  3518.   static PTHREAD_LOCK_TYPE hMutex; 
  3519.   return htsSetLock(&hMutex,i);
  3520. }
  3521. #else
  3522. int _hts_lockdns(int i) {
  3523.   int l=0;
  3524.   if (i>=0)
  3525.     l=i;
  3526.   return l;
  3527. }
  3528. #endif
  3529.  
  3530. // routine pour le cache - retour optionnel α donner α chaque fois
  3531. // NULL: nom non encore testΘ dans le cache
  3532. // si h_length==0 alors le nom n'existe pas dans le dns
  3533. t_hostent* _hts_ghbn(t_dnscache* cache,char* iadr,t_hostent* retour) {
  3534.   // attendre que le cache dns soit prΩt
  3535.   while(_hts_lockdns(-1));  // attendre libΘration
  3536.   _hts_lockdns(1);          // locker
  3537.  
  3538.   while(1) {
  3539.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  3540.       if (cache->host_length>0) {  // entrΘe valide
  3541.         if (retour->h_addr_list[0])
  3542.           memcpy(retour->h_addr_list[0], cache->host_addr, cache->host_length);
  3543.         retour->h_length=cache->host_length;
  3544.       } else if (cache->host_length==0) {  // en cours
  3545.         _hts_lockdns(0);          // dΘlocker
  3546.         return NULL;
  3547.       } else {                    // erreur dans le dns, dΘja vΘrifiΘ
  3548.         if (retour->h_addr_list[0])
  3549.           retour->h_addr_list[0][0]='\0';
  3550.         retour->h_length=0;  // erreur, n'existe pas
  3551.       }
  3552.       _hts_lockdns(0);          // dΘlocker
  3553.       return retour;
  3554.     } else {    // on a pas encore trouvΘ
  3555.       if (cache->n!=NULL) { // chercher encore
  3556.         cache=cache->n;   // suivant!
  3557.       } else {
  3558.         _hts_lockdns(0);          // dΘlocker
  3559.         return NULL;    // non prΘsent        
  3560.       }
  3561.     }    
  3562.   }
  3563. }
  3564.  
  3565. // tester si iadr a dΘja ΘtΘ testΘ (ou en cours de test)
  3566. // 0 non encore
  3567. // 1 ok
  3568. // 2 non prΘsent
  3569. int hts_dnstest(char* _iadr) {
  3570.   char* iadr;
  3571.   t_dnscache* cache=_hts_cache();  // adresse du cache 
  3572.   NOSTATIC_RESERVE(iadr, char, HTS_URLMAXSIZE*2);
  3573.  
  3574.   // sauter user:pass@ Θventuel
  3575.   strcpy(iadr,jump_identification(_iadr));
  3576.   // couper Θventuel :
  3577.   {
  3578.     char *a;
  3579.     if ( (a=jump_toport(iadr)) )
  3580.       *a='\0';
  3581.   }
  3582.  
  3583. #if HTS_WIN
  3584.   if (inet_addr(iadr)!=INADDR_NONE)  // numΘrique
  3585. #else
  3586.   if (inet_addr(iadr)!=(in_addr_t) -1 )  // numΘrique
  3587. #endif
  3588.     return 1;
  3589.  
  3590.   while(_hts_lockdns(-1));  // attendre libΘration
  3591.   _hts_lockdns(1);          // locker
  3592.   while(1) {
  3593.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  3594.       _hts_lockdns(0);          // dΘlocker
  3595.       return 1;    // prΘsent!
  3596.     } else {    // on a pas encore trouvΘ
  3597.       if (cache->n!=NULL) { // chercher encore
  3598.         cache=cache->n;   // suivant!
  3599.       } else {
  3600.         _hts_lockdns(0);          // dΘlocker
  3601.         return 2;    // non prΘsent        
  3602.       }
  3603.     }    
  3604.   }
  3605. }
  3606.  
  3607.  
  3608. t_hostent* vxgethostbyname(char* hostname, void* v_buffer) {
  3609.   t_fullhostent* buffer = (t_fullhostent*) v_buffer;
  3610.   /* Clear */
  3611.   fullhostent_init(buffer);
  3612.  
  3613.   /* Protection */
  3614.   if (!strnotempty(hostname)) {
  3615.     return NULL;
  3616.   }
  3617.  
  3618.   /* 
  3619.     Strip [] if any : [3ffe:b80:1234:1::1] 
  3620.     The resolver doesn't seem to handle IP6 addresses in brackets
  3621.   */
  3622.   if ((hostname[0] == '[') && (hostname[strlen(hostname)-1] == ']')) {
  3623.     char tempo[HTS_URLMAXSIZE*2];
  3624.     tempo[0]='\0';
  3625.     strncat(tempo, hostname+1, strlen(hostname)-2);
  3626.     strcpy(hostname, tempo);
  3627.   }
  3628.  
  3629.   {
  3630. #if HTS_INET6==0
  3631.   /*
  3632.   ipV4 resolver
  3633.     */
  3634.     t_hostent* hp=gethostbyname(hostname);
  3635.     if (hp!=NULL) {
  3636.       if ( (hp->h_length) && ( ((unsigned int) hp->h_length) <= buffer->addr_maxlen) ) {
  3637.         memcpy(buffer->hp.h_addr_list[0], hp->h_addr_list[0], hp->h_length);
  3638.         buffer->hp.h_length = hp->h_length;
  3639.         return &(buffer->hp);
  3640.       }
  3641.     }
  3642. #else
  3643.     /*
  3644.     ipV6 resolver
  3645.     */
  3646.     /*
  3647.     int error_num=0;
  3648.     t_hostent* hp=getipnodebyname(hostname, AF_INET6, AI_DEFAULT, &error_num);
  3649.     oops, deprecated :(
  3650.     */
  3651.     struct addrinfo* res = NULL;
  3652.     struct addrinfo hints;
  3653.     memset(&hints, 0, sizeof(hints));
  3654.     hints.ai_family = PF_UNSPEC;
  3655.     hints.ai_socktype = SOCK_STREAM;
  3656.     hints.ai_protocol = IPPROTO_TCP;
  3657.     if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
  3658.       if (res) {
  3659.         if ( (res->ai_addr) && (res->ai_addrlen) && (res->ai_addrlen <= buffer->addr_maxlen) ) {
  3660.           memcpy(buffer->hp.h_addr_list[0], res->ai_addr, res->ai_addrlen);
  3661.           buffer->hp.h_length = res->ai_addrlen;
  3662.           return &(buffer->hp);
  3663.         }
  3664.       }
  3665.     }
  3666.     if (res) {
  3667.       freeaddrinfo(res);
  3668.     }
  3669.     
  3670. #endif
  3671.   }
  3672.   return NULL;
  3673. }
  3674.  
  3675. // cache dns interne α HTS // ** FREE A FAIRE sur la chaine
  3676. t_hostent* hts_gethostbyname(char* _iadr, void* v_buffer) {
  3677.   char iadr[HTS_URLMAXSIZE*2];
  3678.   t_fullhostent* buffer = (t_fullhostent*) v_buffer;
  3679.   t_dnscache* cache=_hts_cache();  // adresse du cache
  3680.   t_hostent* hp;
  3681.  
  3682.   /* Clear */
  3683.   fullhostent_init(buffer);
  3684.  
  3685.   strcpy(iadr,jump_identification(_iadr));
  3686.   // couper Θventuel :
  3687.   {
  3688.     char *a;
  3689.     if ( (a=jump_toport(iadr)) )
  3690.       *a='\0';
  3691.   }
  3692.  
  3693.   // effacer structure de retour, crΘer nouvelle
  3694.   /*
  3695.   memset(&host, 0, sizeof(t_hostent));  
  3696.   host.h_addr_list=he;
  3697.   he[0]=NULL;
  3698.   he[1]=NULL;  
  3699.   host.h_length=0;  
  3700.   */
  3701.   cache->iadr[0]='*';
  3702.   cache->iadr[1]='\0';
  3703.   
  3704.   /* get IP from the dns cache */
  3705.   hp = _hts_ghbn(cache, iadr, &buffer->hp);
  3706.   if (hp) {
  3707.     if (hp->h_length>0)
  3708.       return hp;
  3709.     else
  3710.       return NULL;    // entrΘe erronΘe (erreur DNS) dans le DNS
  3711.   } else {  // non prΘsent dans le cache dns, tester
  3712.     t_dnscache* c=cache;
  3713.     while(c->n) c=c->n;    // calculer queue
  3714.     
  3715. #if HTS_WIDE_DEBUG    
  3716.     DEBUG_W("gethostbyname\n");
  3717. #endif      
  3718. #if HDEBUG
  3719.     printf("gethostbyname (not in cache)\n");
  3720. #endif
  3721.     {
  3722.       unsigned long inetaddr;
  3723. #if HTS_WIN
  3724.       if ((inetaddr=inet_addr(iadr))==INADDR_NONE) {
  3725. #else
  3726.       if ((inetaddr=inet_addr(iadr))==(in_addr_t) -1 ) {
  3727. #endif        
  3728. #if DEBUGDNS 
  3729.         printf("resolving (not cached) %s\n",iadr);
  3730. #endif
  3731.         hp=vxgethostbyname(iadr, buffer);  // calculer IP host
  3732.       } else {     // numΘrique, convertir sans passer par le dns
  3733.         buffer->hp.h_addr_list[0]=(char*) &inetaddr;
  3734.         buffer->hp.h_length=4;
  3735.         hp=&buffer->hp;
  3736.       }
  3737.     }
  3738. #if HTS_WIDE_DEBUG    
  3739.     DEBUG_W("gethostbyname done\n");
  3740. #endif
  3741.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  3742.     if (cache->n!=NULL) {
  3743.       strcpy(cache->n->iadr,iadr);
  3744.       if (hp!=NULL) {
  3745.         memcpy(cache->n->host_addr, hp->h_addr_list[0], hp->h_length);
  3746.         cache->n->host_length=hp->h_length;
  3747.       } else {
  3748.         cache->n->host_addr[0]='\0';
  3749.         cache->n->host_length=0;  // non existant dans le dns
  3750.       }
  3751.       cache->n->n=NULL;
  3752.       return hp;
  3753.     } else {  // on peut pas noter, mais on peut renvoyer le rΘsultat
  3754.       return hp;
  3755.     }        
  3756.   }  // retour hp du cache
  3757. }
  3758.  
  3759. #else
  3760. HTS_INLINE t_hostent* hts_gethostbyname(char* iadr, t_fullhostent* buffer) {
  3761.   t_hostent* retour;
  3762. #if HTS_WIDE_DEBUG    
  3763.   DEBUG_W("gethostbyname (2)\n");
  3764. #endif
  3765. #if DEBUGDNS 
  3766.     printf("blocking method gethostbyname() in progress for %s\n",iadr);
  3767. #endif
  3768.   retour=vxgethostbyname(jump_identification(iadr), );
  3769. #if HTS_WIDE_DEBUG    
  3770.   DEBUG_W("gethostbyname (2) done\n");
  3771. #endif
  3772.   return retour;
  3773. }
  3774. #endif
  3775.  
  3776.  
  3777. // --- Tracage des mallocs() ---
  3778. #if HTS_TRACE_MALLOC
  3779. typedef struct _mlink {
  3780.   void* adr;
  3781.   int len;
  3782.   int id;
  3783.   struct _mlink* next;
  3784. } mlink;
  3785. mlink trmalloc = {NULL,0,0,NULL};
  3786. int trmalloc_id=0;
  3787.  
  3788. HTS_INLINE void* hts_malloc(size_t len,size_t len2) {
  3789.   mlink* lnk = (mlink*) calloc(1,sizeof(mlink));
  3790.   void*  r   = NULL;
  3791.   if (lnk) {
  3792.     if (len2)
  3793.       r = calloc(len,len2);
  3794.     else
  3795.       r = malloc(len);
  3796.     if (r) {
  3797.       lnk->adr=r;
  3798.       if (len2)
  3799.         lnk->len=len*len2;
  3800.       else
  3801.         lnk->len=len;
  3802.       lnk->id=trmalloc_id++;
  3803.       lnk->next=trmalloc.next;
  3804.       trmalloc.next=lnk;
  3805. #if MEMDEBUG
  3806.       //printf("malloc: %d\n",r);
  3807. #endif
  3808.     } else free(lnk);
  3809.   }
  3810.   return r;
  3811. }
  3812. HTS_INLINE void  hts_free(void* adr) {
  3813.   mlink* lnk = &trmalloc;
  3814.   if (!adr) {
  3815. #if MEMDEBUG
  3816.     printf("* unexpected free() error at %d\n",adr);
  3817. #endif
  3818.     return;
  3819.   }
  3820.   do {
  3821.     if (lnk->next->adr==adr) {
  3822.       mlink* blk_free=lnk->next;
  3823. #if 1
  3824.       lnk->next=lnk->next->next;
  3825.       free((void*) blk_free);
  3826. #else
  3827. #if MEMDEBUG
  3828.       if (blk_free->id==-1) {
  3829.         printf("* memory has already been freed: %d (id=%d)\n",blk_free->adr,blk_free->id);
  3830.       }
  3831. #endif
  3832.       blk_free->id=-1;
  3833. #endif
  3834.       free(adr);
  3835. #if MEMDEBUG
  3836.       //printf("free: %d (id=%d)\n",blk_free->adr,blk_free->id);
  3837. #endif
  3838.       return;
  3839.     }
  3840.     lnk=lnk->next;
  3841.   } while(lnk->next != NULL);
  3842. #if MEMDEBUG
  3843.   printf("* unexpected free() error at %d\n",adr);
  3844. #endif
  3845.   free(adr);
  3846. }
  3847. HTS_INLINE void* hts_realloc(void* adr,size_t len) {
  3848.   mlink* lnk = &trmalloc;
  3849.   do {
  3850.     if (lnk->next->adr==adr) {
  3851.       adr = realloc(adr,len);
  3852.       lnk->next->adr = adr;
  3853.       lnk->next->len = len;
  3854. #if MEMDEBUG
  3855.       //printf("realloc: %d (id=%d)\n",lnk->next->adr,lnk->next->id);
  3856. #endif
  3857.       return adr;
  3858.     }
  3859.     lnk=lnk->next;
  3860.   } while(lnk->next != NULL);
  3861. #if MEMDEBUG
  3862.   printf("* unexpected realloc() error at %d\n",adr);
  3863. #endif
  3864.   return realloc(adr,len);
  3865. }
  3866. // check the malloct() and calloct() trace stack
  3867. void  hts_freeall(void) {
  3868.   while(trmalloc.next) {
  3869. #if MEMDEBUG
  3870.     printf("* block %d\t not released: at %d\t (%d\t bytes)\n",trmalloc.next->id,trmalloc.next->adr,trmalloc.next->len);
  3871. #endif
  3872.     if (trmalloc.next->id != -1) {
  3873.       freet(trmalloc.next->adr);
  3874.     }
  3875.   }
  3876. }
  3877. #endif
  3878.  
  3879.  
  3880. // -- divers //
  3881.  
  3882. // cut path and project name
  3883. // patch also initial path
  3884. void cut_path(char* fullpath,char* path,char* pname) {
  3885.   path[0]=pname[0]='\0';
  3886.   if (strnotempty(fullpath)) {
  3887.     if ((fullpath[strlen(fullpath)-1]=='/') || (fullpath[strlen(fullpath)-1]=='\\'))
  3888.       fullpath[strlen(fullpath)-1]='\0';
  3889.     if (strlen(fullpath)>1) {
  3890.       char* a;
  3891.       while( (a=strchr(fullpath,'\\')) ) *a='/';     // remplacer par /
  3892.       a=fullpath+strlen(fullpath)-2;
  3893.       while( (*a!='/') && ( a > fullpath)) a--;
  3894.       if (*a=='/') a++;
  3895.       strcpy(pname,a);
  3896.       strncat(path,fullpath,(int) (a - fullpath));
  3897.     }
  3898.   }
  3899. }
  3900.  
  3901.  
  3902.  
  3903. // -- Gestion protocole ftp --
  3904.  
  3905. #if HTS_WIN
  3906. int ftp_available(void) {
  3907.   return 1;
  3908. }
  3909. #else
  3910. int ftp_available(void) {
  3911.   return 1;   // ok!
  3912.   //return 0;   // SOUS UNIX, PROBLEMES
  3913. }
  3914. #endif
  3915.  
  3916.  
  3917.  
  3918. int hts_init(void) {
  3919.   static int hts_init_ok = 0;
  3920.   if (!hts_init_ok) {
  3921.     hts_init_ok = 1;
  3922.     // default wrappers
  3923.     htswrap_init();
  3924.     htswrap_add("init",htsdefault_init);
  3925.     htswrap_add("free",htsdefault_uninit);
  3926.     htswrap_add("start",htsdefault_start);
  3927.     htswrap_add("change-options",htsdefault_chopt);
  3928.     htswrap_add("end",htsdefault_end);
  3929.     htswrap_add("check-html",htsdefault_checkhtml);
  3930.     htswrap_add("loop",htsdefault_loop);
  3931.     htswrap_add("query",htsdefault_query);
  3932.     htswrap_add("query2",htsdefault_query2);
  3933.     htswrap_add("query3",htsdefault_query3);
  3934.     htswrap_add("check-link",htsdefault_check);
  3935.     htswrap_add("pause",htsdefault_pause);
  3936.     htswrap_add("save-file",htsdefault_filesave);
  3937.     htswrap_add("link-detected",htsdefault_linkdetected);
  3938.     htswrap_add("transfer-status",htsdefault_xfrstatus);
  3939.     htswrap_add("save-name",htsdefault_savename);
  3940.   }
  3941.   
  3942. #if HTS_USEOPENSSL
  3943.   /*
  3944.   Initialize the OpensSSL library
  3945.   */
  3946.   if (!openssl_ctx) {
  3947.     SSL_library_init();
  3948.     SSL_load_error_strings();
  3949.     ERR_load_crypto_strings();
  3950.     ERR_load_SSL_strings();
  3951.     SSLeay_add_ssl_algorithms();
  3952.     // OpenSSL_add_all_algorithms();
  3953.     openssl_ctx = SSL_CTX_new(SSLv23_client_method());
  3954.     if (!openssl_ctx) {
  3955.       fprintf(stderr, "fatal: unable to initialize TLS: SSL_CTX_new(SSLv23_client_method)\n");
  3956.       abort();
  3957.     }
  3958.   }
  3959. #endif
  3960.   
  3961.   /* Init vars and thread-specific values */
  3962.   hts_initvar();
  3963.   
  3964.   return 1;
  3965. }
  3966. int hts_uninit(void) {
  3967.   hts_freevar();
  3968.   /* htswrap_free(); */
  3969.   return 1;
  3970. }
  3971.  
  3972. // defaut wrappers
  3973. void __cdecl htsdefault_init(void) {
  3974. }
  3975. void __cdecl htsdefault_uninit(void) {
  3976.   hts_freevar();
  3977. }
  3978. int __cdecl htsdefault_start(void* opt) {
  3979.   return 1; 
  3980. }
  3981. int __cdecl htsdefault_chopt(void* opt) {
  3982.   return 1;
  3983. }
  3984. int  __cdecl htsdefault_end(void) { 
  3985.   return 1; 
  3986. }
  3987. int __cdecl htsdefault_checkhtml(char* html,int len,char* url_adresse,char* url_fichier) {
  3988.   return 1;
  3989. }
  3990. int __cdecl htsdefault_loop(void* back,int back_max,int back_index,int lien_n,int lien_tot,int stat_time,hts_stat_struct* stats) {    // appelΘ α chaque boucle de HTTrack
  3991.   return 1;
  3992. }
  3993. char* __cdecl htsdefault_query(char* question) {
  3994.   return "";
  3995. }
  3996. char* __cdecl htsdefault_query2(char* question) {
  3997.   return "";
  3998. }
  3999. char* __cdecl htsdefault_query3(char* question) {
  4000.   return "";
  4001. }
  4002. int __cdecl htsdefault_check(char* adr,char* fil,int status) {
  4003.   return -1;
  4004. }
  4005. void __cdecl htsdefault_pause(char* lockfile) {
  4006.   while (fexist(lockfile)) {
  4007.     Sleep(1000);
  4008.   }
  4009. }
  4010. void __cdecl htsdefault_filesave(char* file) {
  4011. }
  4012. int __cdecl htsdefault_linkdetected(char* link) {
  4013.   return 1;
  4014. }
  4015. int __cdecl htsdefault_xfrstatus(void* back) {
  4016.   return 1;
  4017. }
  4018. int __cdecl htsdefault_savename(char* adr_complete,char* fil_complete,char* referer_adr,char* referer_fil,char* save) {
  4019.   return 1;
  4020. }
  4021. // end defaut wrappers
  4022.  
  4023.  
  4024.  
  4025. // Fin
  4026.  
  4027.